diff --git a/Dockerfile b/Dockerfile index a0644ad..6e93629 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,6 +7,6 @@ RUN docker-php-ext-install pdo pdo_mysql zip RUN pecl install xdebug-3.1.1 \ && docker-php-ext-enable xdebug -WORKDIR /code +WORKDIR /app/api COPY --from=composer /usr/bin/composer /usr/bin/composer diff --git a/common/Alias/Controller.php b/common/Alias/Controller.php new file mode 100644 index 0000000..96638ff --- /dev/null +++ b/common/Alias/Controller.php @@ -0,0 +1,30 @@ +mapperFactory = $mapperFactory; + } + protected array $mappers; + public function getMapper(string $name): Mapper + { + if (!class_exists($name)) { + throw new \InvalidArgumentException("Mapper {$name} not found."); + } + if (!isset($this->mappers)) { + $this->mappers = []; + } + if (!isset($this->mappers[$name])) { + $this->mappers[$name] = $this->mapperFactory->get($name); + } + return $this->mappers[$name]; + } +} diff --git a/common/Controller/Auth.php b/common/Controller/Auth.php index 3498b39..fac4dd1 100644 --- a/common/Controller/Auth.php +++ b/common/Controller/Auth.php @@ -5,9 +5,8 @@ use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ResponseInterface as Response; use Incoviba\API\Common\Define\Controller\Json; use Incoviba\API\Common\Service\Auth as Service; -use Incoviba\API\Common\Factory\Model as Factory; -use Incoviba\Auth\User; -use Incoviba\Auth\Login; +use Incoviba\API\Common\Service\Login as LoginService; +use Incoviba\Mapper\User as UserMapper; class Auth { use Json; @@ -16,19 +15,19 @@ class Auth { $key = $service->generate(); return $this->withJson($response, compact('key')); } - public function login(Request $request, Response $response, Service $service, Factory $factory): Response { + public function login(Request $request, Response $response, Service $service, LoginService $loginService, UserMapper $mapper): Response { $post = json_decode($request->getBody()); - $user = $factory->find(User::class)->where([['name', $post->name]])->one(); + $user = $mapper->fetchByName($post->name); $output = [ 'login' => false, 'token' => '' ]; - if ($user->enabled == 0) { - $this->withJson($response, $output); + if (!$user or !$user->enabled) { + return $this->withJson($response, $output); } if ($user->validate($post->password)) { $token = $service->generateToken(); - $status = $user->setToken($token->selector, $token->token); + $status = $loginService->setToken($user, $token->selector, $token->token); if ($status['logged_in']) { $output['login'] = true; $output['token'] = $token->full; @@ -37,46 +36,41 @@ class Auth { } return $this->withJson($response, $output); } - protected function getLogin(object $post, Factory $factory): bool|Login { - list($selector, $token) = explode(':', $post->token); //Token from the cookie - $login = $factory->find(Login::class)->where([['selector', $selector]])->one(); - if ($login === false or !password_verify($token, $login->token) or !$login->isValid()) { - return false; - } - return $login; - } - public function validate(Request $request, Response $response, Factory $factory): Response { + public function validate(Request $request, Response $response, LoginService $loginService): Response { $post = json_decode($request->getBody()); - if (!$this->getLogin($post, $factory)) { - return $this->withJson($response, ['token' => $post->token, 'error' => 'Not authorized'], 401); + $valid = $loginService->validate($post); + $output = [ + 'token' => $post->token + ]; + if ($valid) { + $output['status'] = 'Authorized'; + } else { + $output['error'] = 'Not authorized'; } - return $this->withJson($response, ['token' => $post->token, 'status' => 'Authorized']); + return $this->withJson($response, $output, $valid ? 200 : 401); } - public function user(Request $request, Response $response, Factory $factory): Response { + public function user(Request $request, Response $response, LoginService $loginService): Response { $post = json_decode($request->getBody()); - $login = $this->getLogin($post, $factory); - if (!$login) { + $user = $loginService->getUser($post); + if (!$user) { return $this->withJson($response, ['token' => $post->token, 'error' => 'Not authorized'], 401); } $output = [ 'token' => $post->token, - 'user' => $login->user()->name + 'user' => $user->name ]; return $this->withJson($response, $output); } - public function logout(Request $request, Response $response, Factory $factory): Response { + public function logout(Request $request, Response $response, LoginService $loginService): Response { $post = json_decode($request->getBody()); - list($selector, $token) = explode(':', $post->token); //Token from the cookie - $login = $factory->find(Login::class)->where([['selector', $selector]])->one(); + $user = $loginService->getUser($post); + if (!$user) { + return $this->withJson($response, ['logout' => true]); + } $output = [ 'token' => $post->token, - 'logout' => false + 'logout' => $loginService->logout($user) ]; - if ($login !== false) { - $output['logout'] = $login->user()->logout(); - } else { - $output['logout'] = true; - } return $this->withJson($response, $output); } } diff --git a/common/Controller/Proyectos.php b/common/Controller/Proyectos.php index 6e7136b..1eee921 100644 --- a/common/Controller/Proyectos.php +++ b/common/Controller/Proyectos.php @@ -1,93 +1,141 @@ find(Proyecto::class)->array(); - $base_url = str_replace('/proyectos', '{URL}', $request->getUri()); - array_walk($proyectos, function (&$item) use ($base_url) { - $link = [ - 'rel' => 'proyecto', - 'title' => $item['descripcion'], - 'href' => str_replace('{URL}', "/proyecto/{$item['id']}", $base_url) - ]; - $item['link'] = $link; - }); - return $this->withJson($response, compact('proyectos')); - } - public function show(Request $request, Response $response, Factory $factory, $proyecto_id): Response { - $proyecto = $factory->find(Proyecto::class)->one($proyecto_id); - $output = [ - 'input' => $proyecto_id, - 'proyecto' => $proyecto->toArray(), - 'link' => [ - 'rel' => 'proyectos', - 'title' => 'Proyectos', - 'href' => str_replace("/proyecto/{$proyecto_id}", '/proyectos', $request->getUri()) - ] - ]; - $output['links'] = [ - [ - 'rel' => 'inmobiliaria', - 'title' => $proyecto->inmobiliaria()->abreviacion, - 'href' => str_replace("/proyecto/{$proyecto_id}", "/inmobiliaria/{$proyecto->inmobiliaria()->rut}", $request->getUri()) - ], - [ - 'rel' => 'direccion', - 'title' => $proyecto->direccion()->calle, - 'href' => str_replace("/proyecto/{$proyecto_id}", "/direccion/{$proyecto->direccion}", $request->getUri()) - ] - ]; - return $this->withJson($response, $output); - } - public function add(Request $request, Response $response, Factory $factory): Response { - $post = $request->getParsedBody(); - $output = [ - 'input' => $post - ]; - if (in_array('proyectos', $post)) { - $output['proyectos'] = []; - foreach ($post['proyectos'] as $input) { - $proyecto = Proyecto::add($factory, $input); - $proyecto []= [ - 'proyecto' => $proyecto->toArray(), - 'created' => $proyecto->is_new() ? $proyecto->save() : false - ]; - } - } elseif (in_array('proyecto', $post)) { - $proyecto = Proyecto::add($factory, $post); - $output['proyecto'] = $proyecto; - $output['created'] = $proyecto->is_new() ? $proyecto->save() : false; +class Proyectos extends Controller { + public function __invoke(Request $request, Response $response): Response { + $proyectos = $this->getMapper(ProyectoMapper::class)->fetchAll(); + usort($proyectos, function($a, $b) { + return strcmp($a->descripcion, $b->descripcion); + }); + $proyectos = json_decode(json_encode($proyectos), JSON_OBJECT_AS_ARRAY); + foreach ($proyectos as &$proyecto) { + $proyecto['ventas'] = $this->getMapper(VentaMapper::class)->fetchCountByProyecto($proyecto['id']); + } + return $this->withJson($response, compact('proyectos')); + } + public function show(Request $request, Response $response, Factory $factory, $proyecto_id): Response { + $proyecto = $factory->find(Proyecto::class)->one($proyecto_id); + $output = [ + 'input' => $proyecto_id, + 'proyecto' => $proyecto->toArray(), + 'link' => [ + 'rel' => 'proyectos', + 'title' => 'Proyectos', + 'href' => str_replace("/proyecto/{$proyecto_id}", '/proyectos', $request->getUri()) + ] + ]; + $output['links'] = [ + [ + 'rel' => 'inmobiliaria', + 'title' => $proyecto->inmobiliaria()->abreviacion, + 'href' => str_replace("/proyecto/{$proyecto_id}", "/inmobiliaria/{$proyecto->inmobiliaria()->rut}", $request->getUri()) + ], + [ + 'rel' => 'direccion', + 'title' => $proyecto->direccion()->calle, + 'href' => str_replace("/proyecto/{$proyecto_id}", "/direccion/{$proyecto->direccion}", $request->getUri()) + ] + ]; + return $this->withJson($response, $output); + } + public function add(Request $request, Response $response, Factory $factory): Response { + $post = $request->getParsedBody(); + $output = [ + 'input' => $post + ]; + if (in_array('proyectos', $post)) { + $output['proyectos'] = []; + foreach ($post['proyectos'] as $input) { + $proyecto = Proyecto::add($factory, $input); + $proyecto []= [ + 'proyecto' => $proyecto->toArray(), + 'created' => $proyecto->is_new() ? $proyecto->save() : false + ]; + } + } elseif (in_array('proyecto', $post)) { + $proyecto = Proyecto::add($factory, $post); + $output['proyecto'] = $proyecto; + $output['created'] = $proyecto->is_new() ? $proyecto->save() : false; + } + return $this->withJson($response, $output); + } + public function edit(Request $request, Response $response, Factory $factory, $proyecto_id): Response { + $post = $request->getParsedBody(); + $input = compact('proyecto_id', 'post'); + $proyecto = $factory->find(Proyecto::class)->one($proyecto_id); + $output = [ + 'input' => $input, + 'proyecto' => $proyecto->toArray() + ]; + $output['edited'] = $proyecto->edit($post); + $output['changes'] = $proyecto->toArray(); + return $this->withJson($response, $output); + } + public function delete(Request $request, Response $response, Factory $factory, $proyecto_id): Response { + $proyecto = $factory->find(Proyecto::class)->one($proyecto_id); + $output = [ + 'input' => $proyecto_id, + 'proyecto' => $proyecto->toArray() + ]; + $output['deleted'] = $proyecto->delete(); + return $this->withJson($response, $output); + } + + public function ventas(Request $request, Response $response, $proyecto_id): Response + { + $proyecto = $this->getMapper(ProyectoMapper::class)->fetchById($proyecto_id); + $ventas = $this->getMapper(VentaMapper::class)->fetchActivaByProyecto($proyecto_id); + $output = ['proyecto' => json_decode(json_encode($proyecto), JSON_OBJECT_AS_ARRAY)]; + $output['proyecto']['ventas'] = json_decode(json_encode($ventas), JSON_OBJECT_AS_ARRAY); + foreach ($ventas as $i => $venta) { + $estado = $this->getMapper(EstadoVenta::class)->fetchLastByVenta($venta->id); + $output['proyecto']['ventas'][$i]['estado'] = $estado; + } + return $this->withJson($response, $output); + } + public function precios(Request $request, Response $response, Format $format, $proyecto_id): Response { + $proyecto = $this->getMapper(ProyectoMapper::class)->fetchById($proyecto_id); + $output = json_decode(json_encode(compact('proyecto')), JSON_OBJECT_AS_ARRAY); + $tipos = $this->getMapper(TipoMapper::class)->fetchByProyecto($proyecto_id); + usort($tipos, function($a, $b) { + $t = strcmp($a->tipo->id, $b->tipo->id); + if ($t === 0) { + return strcmp($a->nombre, $b->nombre); + } + return $t; + }); + $output['proyecto']['tipos'] = json_decode(json_encode($tipos), JSON_OBJECT_AS_ARRAY); + foreach ($tipos as $i => $tipo) { + $unidades = $this->getMapper(UnidadMapper::class)->fetchByTipo($tipo->id); + $output['proyecto']['tipos'][$i]['unidades'] = json_decode(json_encode($unidades), JSON_OBJECT_AS_ARRAY); + foreach ($unidades as $k => $unidad) { + if ($unidad->subtipo === null) { + $output['proyecto']['tipos'][$i]['unidades'][$k]['subtipo'] = $tipo->nombre; + } + $precio = $this->getMapper(PrecioMapper::class)->fetchLastByUnidad($unidad->id); + if (!$precio) { + $output['proyecto']['tipos'][$i]['unidades'][$k]['precio'] = ['valor' => 0, 'formateado' => 0, 'estado' => ['estado' => ['descripcion' => '']]]; + continue; + } + $output['proyecto']['tipos'][$i]['unidades'][$k]['precio'] = json_decode(json_encode($precio), JSON_OBJECT_AS_ARRAY); + $output['proyecto']['tipos'][$i]['unidades'][$k]['precio']['estado'] = json_decode(json_encode($this->getMapper(EstadoMapper::class)->fetchLastByPrecio($precio->id)), JSON_OBJECT_AS_ARRAY); + $output['proyecto']['tipos'][$i]['unidades'][$k]['precio']['formateado'] = $format->uf($precio->valor); + } + } + return $this->withJson($response, $output); } - return $this->withJson($response, $output); - } - public function edit(Request $request, Response $response, Factory $factory, $proyecto_id): Response { - $post = $request->getParsedBody(); - $input = compact('proyecto_id', 'post'); - $proyecto = $factory->find(Proyecto::class)->one($proyecto_id); - $output = [ - 'input' => $input, - 'proyecto' => $proyecto->toArray() - ]; - $output['edited'] = $proyecto->edit($post); - $output['changes'] = $proyecto->toArray(); - return $this->withJson($response, $output); - } - public function delete(Request $request, Response $response, Factory $factory, $proyecto_id): Response { - $proyecto = $factory->find(Proyecto::class)->one($proyecto_id); - $output = [ - 'input' => $proyecto_id, - 'proyecto' => $proyecto->toArray() - ]; - $output['deleted'] = $proyecto->delete(); - return $this->withJson($response, $output); - } } diff --git a/common/Controller/Proyectos/Cierres.php b/common/Controller/Proyectos/Cierres.php index 40278b1..937b1b6 100644 --- a/common/Controller/Proyectos/Cierres.php +++ b/common/Controller/Proyectos/Cierres.php @@ -3,27 +3,34 @@ namespace Incoviba\API\Common\Controller\Proyectos; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ResponseInterface as Response; -use Incoviba\API\Common\Factory\Model as Factory; use Incoviba\API\Common\Define\Controller\Json; -use Incoviba\Proyecto\Proyecto; +use Incoviba\Mapper\Proyecto as ProyectoMapper; +use Incoviba\Mapper\Cierre as CierreMapper; class Cierres { use Json; - public function __invoke(Request $request, Response $response, Factory $factory): Response { - $proyectos = $factory->find(Proyecto::class)->many(); + public function __invoke(Request $request, Response $response, ProyectoMapper $proyectoMapper, CierreMapper $cierreMapper): Response { + $proyectos = $proyectoMapper->fetchAll(); $cierres = []; + function filter_cierres($cierres, $estado) { + return array_filter($cierres, function ($item) use ($estado) { + return $item->estado()->tipo->descripcion === $estado; + }); + } foreach ($proyectos as $proyecto) { - if (count($proyecto->cierres()) == 0) { + $cs = $cierreMapper->fetchByProyecto($proyecto->id); + if (count($cs) == 0) { continue; } + $pendientes = filter_cierres($cs, 'pendiente'); $cierres[$proyecto->descripcion] = [ 'proyecto' => $proyecto->descripcion, - 'total' => count($proyecto->cierres()), - 'promesados' => count($proyecto->cierres(3)), - 'rechazados' => count($proyecto->cierres(-1)), - 'pendientes' => count($proyecto->cierres(2)), - 'ultimo_pendiente' => (count($proyecto->cierres(2)) > 0) ? $proyecto->cierres(2)[0]->periodo() : 0 + 'total' => count($cs), + 'promesados' => count(filter_cierres($cs, 'promesado')), + 'rechazados' => count(filter_cierres($cs, 'rechazado')), + 'pendientes' => count($pendientes), + 'ultimo_pendiente' => (count($pendientes) > 0) ? $pendientes[0]->periodo() : 0 ]; } return $this->withJson($response, compact('cierres')); diff --git a/common/Controller/Proyectos/Cuotas.php b/common/Controller/Proyectos/Cuotas.php index de76d07..8a24dd1 100644 --- a/common/Controller/Proyectos/Cuotas.php +++ b/common/Controller/Proyectos/Cuotas.php @@ -1,31 +1,25 @@ find(Proyecto::class)->many(); - $cuotas = []; - foreach ($proyectos as $proyecto) { - foreach ($proyecto->cuotas() as $cuota) { - $cuotas []= $cuota->toArray(); - } - } - return $this->withJson($response, ['cuotas' => $cuotas]); - } - public function mes(Request $request, Response $response, Factory $factory): Response { - $proyectos = $factory->find(Proyecto::class)->many(); + public function mes(Request $request, Response $response, ProyectoMapper $proyectoMapper, CuotaMapper $cuotaMapper): Response { + $proyectos = $proyectoMapper->fetchAll(); $dias = []; foreach ($proyectos as $proyecto) { - foreach ($proyecto->cuotasMes() as $cuota) { - $f = $cuota->pago()->fecha(); + $cuotas = $cuotaMapper->fetchByProyectoAndMes($proyecto->id, new \DateTimeImmutable()); + foreach ($cuotas as $cuota) { + $f = Carbon::createFromTimestamp($cuota->pago->fecha->getTimestamp()); if ($f->isoWeekday() == 6 or $f->isoWeekDay() == 7) { $f = $f->copy()->addDays(2)->startOfWeek(); } @@ -42,21 +36,21 @@ class Cuotas { uksort($dias, function($a, $b) { return strcmp($a, $b); }); - return $this->withJson($response, ['proyecto' => $proyecto->toArray(), 'dias' => $dias]); + return $this->withJson($response, ['dias' => $dias]); } - public function hoy(Request $request, Response $response, Factory $factory): Response { - $proyectos = $factory->find(Proyecto::class)->many(); + public function hoy(Request $request, Response $response, ProyectoMapper $proyectoMapper, CuotaMapper $cuotaMapper): Response { + $proyectos = $proyectoMapper->fetchAll(); $hoy = 0; foreach ($proyectos as $proyecto) { - $hoy += count($proyecto->cuotasHoy()); + $hoy += count($cuotaMapper->fetchByProyectoAndFecha($proyecto->id, new \DateTimeImmutable())); } return $this->withJson($response, ['hoy' => $hoy]); } - public function pendientes(Request $request, Response $response, Factory $factory): Response { - $proyectos = $factory->find(Proyecto::class)->many(); + public function pendientes(Request $request, Response $response, ProyectoMapper $proyectoMapper, CuotaMapper $cuotaMapper): Response { + $proyectos = $proyectoMapper->fetchAll(); $pendientes = 0; foreach ($proyectos as $proyecto) { - $pendientes += count($proyecto->cuotasPendientes()); + $pendientes += count($cuotaMapper->fetchByProyectoAndPendiente($proyecto->id)); } return $this->withJson($response, ['pendientes' => $pendientes]); } diff --git a/common/Controller/Ventas.php b/common/Controller/Ventas.php index d95ff6b..455ba4e 100644 --- a/common/Controller/Ventas.php +++ b/common/Controller/Ventas.php @@ -6,150 +6,153 @@ use Psr\Http\Message\ResponseInterface as Response; use Incoviba\API\Common\Define\Controller\Json; use Incoviba\API\Common\Factory\Model as Factory; use Incoviba\Venta\Venta; +use Incoviba\Mapper\Venta as VentaMapper; class Ventas { - use Json; + use Json; - public function __invoke(Request $request, Response $response, Factory $factory): Response { - $ventas = $factory->find(Venta::class)->array(); - $url = '' . $request->getUri(); - array_walk($ventas, function (&$item) use ($url) { - $item['link'] = [ - 'rel' => 'venta', - 'title' => 'Venta', - 'href' => str_replace('/ventas', "/venta/{$item['id']}", $url) - ]; - }); - return $this->withJson($response, compact('ventas')); - } - public function show(Request $request, Response $response, Factory $factory, $venta_id): Response { - $venta = $factory->find(Venta::class)->one($venta_id); - $output = [ - 'input' => $venta_id, - 'venta' => $venta->toArray(), - 'link' => [ - 'rel' => 'ventas', - 'title' => 'Ventas', - 'href' => str_replace("/venta/{$venta_id}", '/ventas', $request->getUri()) - ] - ]; - $output['links'] = [ - [ - 'rel' => 'propietario', - 'title' => $venta->propietario()->nombreCompleto(), - 'href' => str_replace("/venta/{$venta_id}", "/propietario/{$venta->propietario}", $request->getUri()) - ], - [ - 'rel' => 'propiedad', - 'title' => 'Propiedad', - 'href' => str_replace("/venta/{$venta_id}", "/propiedad/{$venta->propiedad}", $request->getUri()) - ] - ]; - if ($venta->pie()) { - $output['links'] []= [ - 'rel' => 'pie', - 'title' => 'Pie', - 'href' => str_replace("/venta/{$venta_id}", "/pie/{$venta->pie}", $request->getUri()) - ]; + public function __invoke(Request $request, Response $response, Factory $factory, VentaMapper $mapper): Response { + $ventas = $mapper->fetchAll(); + error_log(var_export($ventas, true)); + $ventas = $factory->find(Venta::class)->array(); + $url = '' . $request->getUri(); + array_walk($ventas, function (&$item) use ($url) { + $item['link'] = [ + 'rel' => 'venta', + 'title' => 'Venta', + 'href' => str_replace('/ventas', "/venta/{$item['id']}", $url) + ]; + }); + return $this->withJson($response, compact('ventas')); } - if ($venta->bono()) { - $output['links'] []= [ - 'rel' => 'bono_pie', - 'title' => 'Bono Pie', - 'href' => str_replace("/venta/{$venta_id}", "/bono/{$venta->bono_pie}", $request->getUri()) - ]; - } - if ($venta->credito()) { - $output['links'] []= [ - 'rel' => 'credito', - 'title' => 'Credito', - 'href' => str_replace("/venta/{$venta_id}", "/credito/{$venta->credito}", $request->getUri()) - ]; - } - if ($venta->escritura()) { - $output['links'] []= [ - 'rel' => 'escritura', - 'title' => 'Escritura', - 'href' => str_replace("/venta/{$venta_id}", "/escritura/{$venta->escritura}", $request->getUri()) - ]; - } - if ($venta->subsidio()) { - $output['links'] []= [ - 'rel' => 'subsidio', - 'title' => 'Subsidio', - 'href' => str_replace("/venta/{$venta_id}", "/subsidio/{$venta->subsidio}", $request->getUri()) - ]; - } - if ($venta->entrega()) { - $output['links'] []= [ - 'rel' => 'entrega', - 'title' => 'Entrega', - 'href' => str_replace("/venta/{$venta_id}", "/entrega/{$venta->entrega}", $request->getUri()) - ]; - } - if ($venta->proyectoAgente()) { - $output['links'] []= [ - 'rel' => 'proyecto_agente', - 'title' => 'Proyecto Agente', - 'href' => str_replace("/venta/{$venta_id}", "/proyecto_agente/{$venta->agente}", $request->getUri()) - ]; - } - if ($venta->promocion()) { - $output['links'] []= [ - 'rel' => 'promocion', - 'title' => 'Promocion', - 'href' => str_replace("/venta/{$venta_id}", "/promocion/{$venta->promocion}", $request->getUri()) - ]; - } - if ($venta->resciliacion()) { - $output['links'] []= [ - 'rel' => 'resciliacion', - 'title' => 'Resciliacion', - 'href' => str_replace("/venta/{$venta_id}", "/resciliacion/{$venta->resciliacion}", $request->getUri()) - ]; - } - return $this->withJson($response, $output); - } - public function add(Request $request, Response $response, Factory $factory): Response { - $post = $request->getParsedBody(); - $output = [ - 'input' => $post - ]; - if (in_array('ventas', $post)) { - $output['ventas'] = []; - foreach ($post['ventas'] as $input) { - $venta = Venta::add($factory, $input); - $venta []= [ + public function show(Request $request, Response $response, Factory $factory, $venta_id): Response { + $venta = $factory->find(Venta::class)->one($venta_id); + $output = [ + 'input' => $venta_id, 'venta' => $venta->toArray(), - 'created' => $venta->is_new() ? $venta->save() : false + 'link' => [ + 'rel' => 'ventas', + 'title' => 'Ventas', + 'href' => str_replace("/venta/{$venta_id}", '/ventas', $request->getUri()) + ] ]; - } - } elseif (in_array('venta', $post)) { - $venta = Venta::add($factory, $post); - $output['venta'] = $venta; - $output['created'] = $venta->is_new() ? $venta->save() : false; + $output['links'] = [ + [ + 'rel' => 'propietario', + 'title' => $venta->propietario()->nombreCompleto(), + 'href' => str_replace("/venta/{$venta_id}", "/propietario/{$venta->propietario}", $request->getUri()) + ], + [ + 'rel' => 'propiedad', + 'title' => 'Propiedad', + 'href' => str_replace("/venta/{$venta_id}", "/propiedad/{$venta->propiedad}", $request->getUri()) + ] + ]; + if ($venta->pie()) { + $output['links'] []= [ + 'rel' => 'pie', + 'title' => 'Pie', + 'href' => str_replace("/venta/{$venta_id}", "/pie/{$venta->pie}", $request->getUri()) + ]; + } + if ($venta->bono()) { + $output['links'] []= [ + 'rel' => 'bono_pie', + 'title' => 'Bono Pie', + 'href' => str_replace("/venta/{$venta_id}", "/bono/{$venta->bono_pie}", $request->getUri()) + ]; + } + if ($venta->credito()) { + $output['links'] []= [ + 'rel' => 'credito', + 'title' => 'Credito', + 'href' => str_replace("/venta/{$venta_id}", "/credito/{$venta->credito}", $request->getUri()) + ]; + } + if ($venta->escritura()) { + $output['links'] []= [ + 'rel' => 'escritura', + 'title' => 'Escritura', + 'href' => str_replace("/venta/{$venta_id}", "/escritura/{$venta->escritura}", $request->getUri()) + ]; + } + if ($venta->subsidio()) { + $output['links'] []= [ + 'rel' => 'subsidio', + 'title' => 'Subsidio', + 'href' => str_replace("/venta/{$venta_id}", "/subsidio/{$venta->subsidio}", $request->getUri()) + ]; + } + if ($venta->entrega()) { + $output['links'] []= [ + 'rel' => 'entrega', + 'title' => 'Entrega', + 'href' => str_replace("/venta/{$venta_id}", "/entrega/{$venta->entrega}", $request->getUri()) + ]; + } + if ($venta->proyectoAgente()) { + $output['links'] []= [ + 'rel' => 'proyecto_agente', + 'title' => 'Proyecto Agente', + 'href' => str_replace("/venta/{$venta_id}", "/proyecto_agente/{$venta->agente}", $request->getUri()) + ]; + } + if ($venta->promocion()) { + $output['links'] []= [ + 'rel' => 'promocion', + 'title' => 'Promocion', + 'href' => str_replace("/venta/{$venta_id}", "/promocion/{$venta->promocion}", $request->getUri()) + ]; + } + if ($venta->resciliacion()) { + $output['links'] []= [ + 'rel' => 'resciliacion', + 'title' => 'Resciliacion', + 'href' => str_replace("/venta/{$venta_id}", "/resciliacion/{$venta->resciliacion}", $request->getUri()) + ]; + } + return $this->withJson($response, $output); + } + public function add(Request $request, Response $response, Factory $factory): Response { + $post = $request->getParsedBody(); + $output = [ + 'input' => $post + ]; + if (in_array('ventas', $post)) { + $output['ventas'] = []; + foreach ($post['ventas'] as $input) { + $venta = Venta::add($factory, $input); + $venta []= [ + 'venta' => $venta->toArray(), + 'created' => $venta->is_new() ? $venta->save() : false + ]; + } + } elseif (in_array('venta', $post)) { + $venta = Venta::add($factory, $post); + $output['venta'] = $venta; + $output['created'] = $venta->is_new() ? $venta->save() : false; + } + return $this->withJson($response, $output); + } + public function edit(Request $request, Response $response, Factory $factory, $venta_id): Response { + $post = $request->getParsedBody(); + $input = compact('venta_id', 'post'); + $venta = $factory->find(Venta::class)->one($venta_id); + $output = [ + 'input' => $input, + 'venta' => $venta->toArray() + ]; + $output['edited'] = $venta->edit($post); + $output['changes'] = $venta->toArray(); + return $this->withJson($response, $output); + } + public function delete(Request $request, Response $response, Factory $factory, $venta_id): Response { + $venta = $factory->find(Venta::class)->one($venta_id); + $output = [ + 'input' => $venta_id, + 'venta' => $venta->toArray() + ]; + $output['deleted'] = $venta->delete(); + return $this->withJson($response, $output); } - return $this->withJson($response, $output); - } - public function edit(Request $request, Response $response, Factory $factory, $venta_id): Response { - $post = $request->getParsedBody(); - $input = compact('venta_id', 'post'); - $venta = $factory->find(Venta::class)->one($venta_id); - $output = [ - 'input' => $input, - 'venta' => $venta->toArray() - ]; - $output['edited'] = $venta->edit($post); - $output['changes'] = $venta->toArray(); - return $this->withJson($response, $output); - } - public function delete(Request $request, Response $response, Factory $factory, $venta_id): Response { - $venta = $factory->find(Venta::class)->one($venta_id); - $output = [ - 'input' => $venta_id, - 'venta' => $venta->toArray() - ]; - $output['deleted'] = $venta->delete(); - return $this->withJson($response, $output); - } } diff --git a/common/Factory/Mapper.php b/common/Factory/Mapper.php new file mode 100644 index 0000000..3d7c44e --- /dev/null +++ b/common/Factory/Mapper.php @@ -0,0 +1,22 @@ +container = $container; + } + + public function get(string $name): BaseMapper + { + if (!class_exists($name)) { + throw new \InvalidArgumentException(); + } + return $this->container->get($name); + } +} diff --git a/common/Service/Format.php b/common/Service/Format.php new file mode 100644 index 0000000..3c6ed23 --- /dev/null +++ b/common/Service/Format.php @@ -0,0 +1,14 @@ +userMapper = $userMapper; + $this->loginMapper = $loginMapper; + $this->configMapper = $configMapper; + } + + public function setToken(User $user, string $selector, string $token) + { + $this->logout($user); + $expiration = $this->configMapper->fetchByName('cookie_expiration_time'); + $data = [ + 'user_id' => $user->id, + 'time' => (new \DateTimeImmutable())->format('Y-m-d H:i:s '), + 'selector' => $selector, + 'token' => $token, + 'status' => 1 + ]; + $status = false; + try { + $login = $this->loginMapper->create($data); + $status = $this->loginMapper->save($login); + } catch (\PDOException $e) { + $login = false; + } + $output = [ + 'input' => $data, + 'login' => $login, + 'logged_in' => $status + ]; + if ($login !== false) { + $output['expires'] = $login->time->modify("+{$expiration->value} second")->getTimestamp(); + } + return $output; + } + public function logout(User $user): bool + { + $logins = $this->validLogins($user); + if ($logins === false or count($logins) === 0) { + return true; + } + $bool = true; + foreach ($logins as $login) { + $login->status = false; + $bool &= $this->loginMapper->save($login); + } + return $bool; + } + public function validLogins(User $user): bool|array { + return $this->loginMapper->fetchActiveByUser($user->id); + } + public function validate($request): bool + { + list($selector, $token) = explode(':', $request->token); + $login = $this->loginMapper->fetchBySelector($selector); + if (!$login or !$login->status or !password_verify($token, $login->token)) { + return false; + } + $expiration = $this->configMapper->fetchByName('cookie_expiration_time'); + if ((Carbon::createFromTimestamp($login->time->getTimestamp()))->diffInSeconds() > $expiration->value) { + $login->status = false; + $this->loginMapper->save($login); + return false; + } + return true; + } + public function getUser($request): User|bool + { + list($selector, $token) = explode(':', $request->token); + $login = $this->loginMapper->fetchBySelector($selector); + if (!$login or !$login->status) { + return false; + } + return $login->user; + } +} diff --git a/composer.json b/composer.json index 94580dd..a1038c1 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "zeuxisoo/slim-whoops": "^0.7.3", "slim/psr7": "^1.5", "nesbot/carbon": "^2.54", - "j4mie/paris": "^1.5" + "doctrine/dbal": "^3.3" }, "require-dev": { "phpunit/phpunit": "^9.5", diff --git a/nginx.conf b/nginx.conf index 7353076..50041ef 100644 --- a/nginx.conf +++ b/nginx.conf @@ -1,10 +1,10 @@ server { - listen 80; + listen 81; server_name api; index index.php; - error_log /code/logs/error.log; - access_log /code/logs/access.log; - root /code/public; + error_log /var/log/nginx/api.error.log; + access_log /var/log/nginx/api.access.log; + root /app/api/public; location / { try_files $uri $uri/ /index.php$is_args$args; diff --git a/public/index.php b/public/index.php index 7785631..af792b4 100644 --- a/public/index.php +++ b/public/index.php @@ -1,7 +1,12 @@ run(); +try { + $app->run(); +} catch (Error | Exception $e) { + error_log($e); + echo json_encode(['message' => 'There was an error', 'error' => $e->getMessage(), 'errorCode' => $e->getCode()]); +} diff --git a/resources/routes/proyectos.php b/resources/routes/proyectos.php index 37938fd..73db1b6 100644 --- a/resources/routes/proyectos.php +++ b/resources/routes/proyectos.php @@ -4,19 +4,21 @@ use Incoviba\API\Common\Controller\Proyectos\Cuotas; use Incoviba\API\Common\Controller\Proyectos\Cierres; $app->group('/proyectos', function ($app) { - $app->post('/add[/]', [Proyectos::class, 'add']); - $app->group('/cuotas', function($app) { - $app->get('/hoy[/]', [Cuotas::class, 'hoy']); - $app->get('/mes[/]', [Cuotas::class, 'mes']); - $app->get('/pendientes[/]', [Cuotas::class, 'pendientes']); - }); - $app->group('/cierres', function($app) { - $app->get('[/]', Cierres::class); - }); - $app->get('[/]', Proyectos::class); + $app->post('/add[/]', [Proyectos::class, 'add']); + $app->group('/cuotas', function($app) { + $app->get('/hoy[/]', [Cuotas::class, 'hoy']); + $app->get('/mes[/]', [Cuotas::class, 'mes']); + $app->get('/pendientes[/]', [Cuotas::class, 'pendientes']); + }); + $app->group('/cierres', function($app) { + $app->get('[/]', Cierres::class); + }); + $app->get('[/]', Proyectos::class); }); $app->group('/proyecto/{proyecto_id}', function ($app) { - $app->put('/edit[/]', [Proyectos::class, 'edit']); - $app->delete('/edit[/]', [Proyectos::class, 'delete']); - $app->get('[/]', [Proyectos::class, 'show']); + $app->get('/ventas', [Proyectos::class, 'ventas']); + $app->get('/precios', [Proyectos::class, 'precios']); + $app->put('/edit[/]', [Proyectos::class, 'edit']); + $app->delete('/edit[/]', [Proyectos::class, 'delete']); + $app->get('[/]', [Proyectos::class, 'show']); }); diff --git a/setup/app.php b/setup/app.php index f4f511b..8fbd666 100644 --- a/setup/app.php +++ b/setup/app.php @@ -49,5 +49,7 @@ if (file_exists($folder)) { $app->addRoutingMiddleware(); -include_once 'databases.php'; +//include_once 'databases.php'; include_once 'router.php'; + +return $app; diff --git a/setup/databases.php b/setup/databases.php index ae71fce..e155422 100644 --- a/setup/databases.php +++ b/setup/databases.php @@ -5,7 +5,7 @@ foreach ($database->databases as $name => $settings) { switch (strtolower($settings->engine)) { case 'mysql': $dsn = "mysql:host={$settings->host->name};dbname={$settings->name}" . (isset($settings->host->port) ? ';port=' . $settings->host->port : ''); - ORM::configure([ + Orm::configure([ 'connection_string' => $dsn, 'username' => $settings->user->name, 'password' => $settings->user->password @@ -13,12 +13,12 @@ foreach ($database->databases as $name => $settings) { break; } if (isset($settings->logging) and $settings->logging) { - ORM::configure('logging', true, $name); + Orm::configure('logging', true, $name); } if (isset($settings->caching) and $settings->caching) { - ORM::configure('caching', true, $name); + Orm::configure('caching', true, $name); } } if (isset($database->short_names) and $database->short_names) { - Model::$short_table_names = true; + Orm::$short_table_names = true; } diff --git a/setup/settings/02_databases.php b/setup/settings/02_databases.php index 15bb617..369ac5e 100644 --- a/setup/settings/02_databases.php +++ b/setup/settings/02_databases.php @@ -4,6 +4,7 @@ return [ $arr = [ 'default' => (object) [ 'engine' => 'mysql', + 'driver' => 'pdo_mysql', 'host' => (object) [ 'name' => $_ENV['MYSQL_HOST'] ?? 'db' ], diff --git a/setup/setups/03_database.php b/setup/setups/03_database.php new file mode 100644 index 0000000..4b5dd4e --- /dev/null +++ b/setup/setups/03_database.php @@ -0,0 +1,19 @@ + function(ContainerInterface $container) { + $config = $container->get('database')->databases['default']; + $conn = [ + 'dbname' => $config->name, + 'user' => $config->user->name, + 'password' => $config->user->password, + 'host' => $config->host->name, + 'driver' => $config->driver + ]; + if (isset($config->host->port)) { + $conn['port'] = $config->host->port; + } + return \Doctrine\DBAL\DriverManager::getConnection($conn); + } +]; diff --git a/src/Mapper/AgenteTipo.php b/src/Mapper/AgenteTipo.php new file mode 100644 index 0000000..b63b85d --- /dev/null +++ b/src/Mapper/AgenteTipo.php @@ -0,0 +1,23 @@ +id = $row['id']; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/Banco.php b/src/Mapper/Banco.php new file mode 100644 index 0000000..cd456ca --- /dev/null +++ b/src/Mapper/Banco.php @@ -0,0 +1,25 @@ +id = $row['id']; + $model->nombre = $row['nombre']; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/BonoPie.php b/src/Mapper/BonoPie.php new file mode 100644 index 0000000..ec27ba4 --- /dev/null +++ b/src/Mapper/BonoPie.php @@ -0,0 +1,22 @@ +id = $row['id']; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/Cierre.php b/src/Mapper/Cierre.php new file mode 100644 index 0000000..fdbc878 --- /dev/null +++ b/src/Mapper/Cierre.php @@ -0,0 +1,38 @@ +id = $row['id']; + $model->proyecto = $this->getMapper(Proyecto::class)->fetchById($row['proyecto']); + $model->precio = $row['precio']; + $model->fecha = new \DateTimeImmutable($row['fecha']); + $model->relacionado = $row['relacionado'] != 0; + $model->propietario = $row['propietario'] == 0 ? 0 : $this->getMapper(Propietario::class)->fetchById($row['propietario']); + $model->setFactory($this->factory); + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } + + public function fetchByProyecto(int $proyecto_id): array + { + $qb = $this->connection->createQueryBuilder() + ->select('*') + ->from($this->table) + ->where('proyecto = ?'); + return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$proyecto_id])->fetchAllAssociative()); + } +} diff --git a/src/Mapper/Config.php b/src/Mapper/Config.php new file mode 100644 index 0000000..fe4ad36 --- /dev/null +++ b/src/Mapper/Config.php @@ -0,0 +1,33 @@ +id = $row['id']; + $model->name = $row['name']; + $model->value = $row['value']; + return $model; + } + public function save(Model $model): bool + { + return true; + } + + public function fetchByName(string $name): ConfigModel + { + $qb = $this->connection->createQueryBuilder() + ->select('*') + ->from($this->table) + ->where('name = ?'); + return $this->load(($this->connection->executeQuery($qb, [$name]))->fetchAssociative()); + } +} diff --git a/src/Mapper/Credito.php b/src/Mapper/Credito.php new file mode 100644 index 0000000..4d1c7ee --- /dev/null +++ b/src/Mapper/Credito.php @@ -0,0 +1,22 @@ +id = $row['id']; + return $credito; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/Cuota.php b/src/Mapper/Cuota.php new file mode 100644 index 0000000..9b5c675 --- /dev/null +++ b/src/Mapper/Cuota.php @@ -0,0 +1,93 @@ +id = $row['id']; + $model->pie = $this->getMapper(Pie::class)->fetchById($row['pie']); + $model->fecha = new \DateTimeImmutable($row['fecha']); + $model->valor = $row['valor_$']; + $model->estado = $row['estado']; + $model->banco = ($row['banco'] != '') ? $this->getMapper(Banco::class)->fetchById($row['banco']) : null; + $estado = new CuotaModel\Estado(); + $estado->fecha_pago = ($row['fecha_pago']) ? new \DateTimeImmutable($row['fecha_pago']) : null; + $estado->abonado = $row['abonado']; + $estado->fecha_abono = ($row['fecha_abono']) ? new \DateTimeImmutable($row['fecha_abono']) : null; + $model->estado_cuota = $estado; + $model->uf = $row['uf']; + $model->pago = $this->getMapper(Pago::class)->fetchById($row['pago']); + $model->numero = $row['numero']; + return $model; + } + + public function save(Model $model): bool + { + return true; + } + + public function fetchByProyecto(int $proyecto_id): array + { + $qb = $this->connection->createQueryBuilder() + ->select('a.*') + ->from($this->table, 'a') + ->innerJoin('a', 'venta', 'v', 'v.pie = a.pie') + ->innerJoin('v', 'propiedad', 'p', 'p.id = v.propiedad') + ->innerJoin('p', 'unidad', 'u', 'u.id = p.unidad_principal') + ->innerJoin('u', 'proyecto_tipo_unidad', 'ptu', 'ptu.id = u.pt') + ->where('ptu.proyecto = ?'); + return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$proyecto_id])->fetchAllAssociative()); + } + public function fetchByProyectoAndFecha(int $proyecto_id, \DateTimeInterface $fecha): array + { + $qb = $this->connection->createQueryBuilder() + ->select('a.*') + ->from($this->table, 'a') + ->innerJoin('a', 'venta', 'v', 'v.pie = a.pie') + ->innerJoin('v', 'propiedad', 'p', 'p.id = v.propiedad') + ->innerJoin('p', 'unidad', 'u', 'u.id = p.unidad_principal') + ->innerJoin('u', 'proyecto_tipo_unidad', 'ptu', 'ptu.id = u.pt') + ->innerJoin('a', 'pago', 'g', 'g.id = a.pago') + ->where('ptu.proyecto = ?') + ->andWhere('g.fecha = ?'); + return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$proyecto_id, $fecha->format('y-m-d')])->fetchAllAssociative()); + } + public function fetchByProyectoAndMes(int $proyecto_id, \DateTimeInterface $mes): array + { + $qb = $this->connection->createQueryBuilder() + ->select('a.*') + ->from($this->table, 'a') + ->innerJoin('a', 'venta', 'v', 'v.pie = a.pie') + ->innerJoin('v', 'propiedad', 'p', 'p.id = v.propiedad') + ->innerJoin('p', 'unidad', 'u', 'u.id = p.unidad_principal') + ->innerJoin('u', 'proyecto_tipo_unidad', 'ptu', 'ptu.id = u.pt') + ->innerJoin('a', 'pago', 'g', 'g.id = a.pago') + ->where('ptu.proyecto = ?') + ->andWhere('g.fecha BETWEEN ? AND ?'); + return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$proyecto_id, $mes->format('y-m-1'), $mes->format('y-m-t')])->fetchAllAssociative()); + } + public function fetchByProyectoAndPendiente(int $proyecto_id): array + { + $qb = $this->connection->createQueryBuilder() + ->select('a.*') + ->from($this->table, 'a') + ->innerJoin('a', 'venta', 'v', 'v.pie = a.pie') + ->innerJoin('v', 'propiedad', 'p', 'p.id = v.propiedad') + ->innerJoin('p', 'unidad', 'u', 'u.id = p.unidad_principal') + ->innerJoin('u', 'proyecto_tipo_unidad', 'ptu', 'ptu.id = u.pt') + ->innerJoin('a', 'pago', 'g', 'g.id = a.pago') + ->leftJoin('g', '(SELECT e1.* FROM estado_pago e1 JOIN (SELECT MAX(id) AS id, pago FROM estado_pago GROUP BY pago) e0 ON e0.id = e1.id)', 'ep', 'ep.pago = g.id') + ->where('ptu.proyecto = ?') + ->andWhere('ep.estado < 1') + ->andWhere('ep.estado >= 0'); + return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$proyecto_id])->fetchAllAssociative()); + } +} diff --git a/src/Mapper/Direccion.php b/src/Mapper/Direccion.php new file mode 100644 index 0000000..69282e8 --- /dev/null +++ b/src/Mapper/Direccion.php @@ -0,0 +1,30 @@ +id = $row['id']; + $model->calle = $row['calle']; + $model->numero = $row['numero']; + $model->extra = $row['extra']; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/Entrega.php b/src/Mapper/Entrega.php new file mode 100644 index 0000000..fb4a2d7 --- /dev/null +++ b/src/Mapper/Entrega.php @@ -0,0 +1,23 @@ +id = $row['id']; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/Escritura.php b/src/Mapper/Escritura.php new file mode 100644 index 0000000..97b958e --- /dev/null +++ b/src/Mapper/Escritura.php @@ -0,0 +1,21 @@ +id = $row['id']; + return $escritura; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/EstadoCierre.php b/src/Mapper/EstadoCierre.php new file mode 100644 index 0000000..520c66f --- /dev/null +++ b/src/Mapper/EstadoCierre.php @@ -0,0 +1,36 @@ +id = $row['id']; + $model->fecha = new \DateTimeImmutable($row['fecha']); + $model->tipo = $this->getMapper(TipoEstadoCierre::class)->fetchById($row['tipo']); + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } + + public function fetchLastByCierre(int $cierre_id) + { + $qb = $this->connection->createQueryBuilder() + ->select('*') + ->from($this->table) + ->where('cierre = ?') + ->orderBy('id', 'desc') + ->setMaxResults(1); + return $this->load($this->connection->executeQuery($qb, [$cierre_id])->fetchAssociative(), true); + } +} diff --git a/src/Mapper/EstadoPrecio.php b/src/Mapper/EstadoPrecio.php new file mode 100644 index 0000000..03bc828 --- /dev/null +++ b/src/Mapper/EstadoPrecio.php @@ -0,0 +1,45 @@ +id = $row['id']; + $model->fecha = new \DateTimeImmutable($row['fecha']); + $model->estado = $this->getMapper(TipoEstadoPrecio::class)->fetchById($row['estado']); + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } + + public function fetchByPrecio(int $precio_id): array + { + $qb = $this->connection->createQueryBuilder() + ->select('*') + ->from($this->table) + ->where('precio = ?'); + return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$precio_id])->fetchAllAssociative()); + } + public function fetchLastByPrecio(int $precio_id): EstadoModel|bool + { + $qb = $this->connection->createQueryBuilder() + ->select('*') + ->from($this->table) + ->where('precio = ?') + ->setMaxResults(1) + ->orderBy('id', 'desc'); + return $this->load($this->connection->executeQuery($qb, [$precio_id])->fetchAssociative()); + } +} diff --git a/src/Mapper/EstadoVenta.php b/src/Mapper/EstadoVenta.php new file mode 100644 index 0000000..e83e3a0 --- /dev/null +++ b/src/Mapper/EstadoVenta.php @@ -0,0 +1,44 @@ +id = $row['id']; + $model->estado = $this->getMapper(TipoEstadoVenta::class)->fetchById($row['estado']); + $model->fecha = new \DateTimeImmutable($row['fecha']); + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } + + public function fetchByVenta(int $venta_id): array + { + $qb = $this->connection->createQueryBuilder() + ->select('*') + ->from($this->table) + ->where('venta = ?'); + return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$venta_id])->fetchAllAssociative()); + } + public function fetchLastByVenta(int $venta_id): BaseModel|bool + { + $qb = $this->connection->createQueryBuilder() + ->select('*') + ->from($this->table) + ->where('venta = ?') + ->setMaxResults(1) + ->orderBy('id', 'desc'); + return $this->load($this->connection->executeQuery($qb, [$venta_id])->fetchAssociative()); + } +} diff --git a/src/Mapper/Inmobiliaria.php b/src/Mapper/Inmobiliaria.php new file mode 100644 index 0000000..2c30d50 --- /dev/null +++ b/src/Mapper/Inmobiliaria.php @@ -0,0 +1,31 @@ +rut = $row['rut']; + $model->dv = $row['dv']; + $model->razon = $row['razon']; + $model->abreviacion = $row['abreviacion']; + $model->cuenta = $row['cuenta']; + $model->banco = ($row['banco']) ? $this->getMapper(Banco::class)->fetchById($row['banco']) : null; + $model->sociedad = $row['sociedad']; + return $model; + } + + public function save(Model $model): bool + { + return false; + } +} diff --git a/src/Mapper/Login.php b/src/Mapper/Login.php new file mode 100644 index 0000000..0d64334 --- /dev/null +++ b/src/Mapper/Login.php @@ -0,0 +1,82 @@ +id = (int) $row['id']; + } + if (!$lazy) { + $model->user = $this->getMapper(User::class)->fetchById((int) $row['user_id']); + } + $model->time = new \DateTimeImmutable($row['time']); + $model->selector = $row['selector']; + $model->token = $row['token']; + $model->status = $row['status'] != 0; + return $model; + } + public function save(Model $model): bool + { + if (!isset($model->id)) { + $qb = $this->connection->createQueryBuilder() + ->insert($this->table) + ->values([ + 'user_id' => '?', + 'time' => '?', + 'selector' => '?', + 'token' => '?', + 'status' => '?' + ]); + return $this->connection->executeStatement($qb, [ + $model->user->id, + $model->time->format('Y-m-d H:i:s'), + $model->selector, + $model->token, + $model->status ? 1 : 0 + ]) > 0; + } + $qb = $this->connection->createQueryBuilder() + ->update($this->table) + ->set('user_id', '?') + ->set('time', '?') + ->set('selector', '?') + ->set('token', '?') + ->set('status', '?') + ->where('id = ?'); + return $this->connection->executeStatement($qb, [ + $model->user->id, + $model->time->format('Y-m-d H:i:s'), + $model->selector, + $model->token, + $model->status ? 1 : 0, + $model->id + ]) > 0; + } + + public function fetchActiveByUser(int $user_id): array + { + $qb = $this->connection->createQueryBuilder() + ->select('*') + ->from($this->table) + ->where('user_id = ?') + ->andWhere('status = 1'); + return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$user_id])->fetchAllAssociative()); + } + public function fetchBySelector(string $selector): LoginModel|bool + { + $qb = $this->connection->createQueryBuilder() + ->select('*') + ->from($this->table) + ->where('selector = ?'); + return $this->load($this->connection->executeQuery($qb, [$selector])->fetchAssociative()); + } +} diff --git a/src/Mapper/Mapper.php b/src/Mapper/Mapper.php new file mode 100644 index 0000000..25658a2 --- /dev/null +++ b/src/Mapper/Mapper.php @@ -0,0 +1,80 @@ +factory = $container->get(Factory::class); + $this->connection = $container->get(Connection::class); + } + + protected string $id = 'id'; + protected string $table = ''; + + public function fetch(string $name, array $params = []) + { + $method = 'fetch' . str_replace(' ', '', ucwords(str_replace('_', ' ', $name))); + if (method_exists($this, $method)) { + return call_user_func_array([$this, $method], $params); + } + throw new \InvalidArgumentException("Method {$method} not found in " . get_called_class()); + } + public function fetchById(int $id): Model|bool + { + $qb = $this->connection->createQueryBuilder() + ->select('*') + ->from($this->table) + ->where("{$this->id} = ?"); + $row = $this->connection->executeQuery($qb, [$id])->fetchAssociative(); + return $this->load($row); + } + public function fetchAll(): array + { + $qb = $this->connection->createQueryBuilder() + ->select('*') + ->from($this->table); + $row = $this->connection->executeQuery($qb)->fetchAllAssociative(); + return array_map([$this, 'load'], $row); + } + + public function getMapper(string $name): Mapper + { + if (!class_exists($name)) { + throw new \InvalidArgumentException("Mapper {$name} does not exist"); + } + if (!isset($this->mappers)) { + $this->mappers = []; + } + if (!isset($this->mappers[$name])) { + $this->mappers[$name] = $this->factory->get($name); + } + return $this->mappers[$name]; + } + + public function create(array $data): Model|bool + { + $qb = $this->connection->createQueryBuilder() + ->select('*') + ->from($this->table); + foreach (array_keys($data) as $field) { + $qb = $qb->andWhere("{$field} = ?"); + } + $row = ($this->connection->executeQuery($qb, array_values($data)))->fetchAssociative(); + if (!$row) { + $row = $data; + } + return $this->load($row); + } + + abstract protected function load(array|bool $row, bool $lazy = false): Model|bool; + abstract public function save(Model $model): bool; +} diff --git a/src/Mapper/Pago.php b/src/Mapper/Pago.php new file mode 100644 index 0000000..436e96f --- /dev/null +++ b/src/Mapper/Pago.php @@ -0,0 +1,32 @@ +id = $row['id']; + $model->valor = $row['valor']; + $model->banco = ($row['banco']) ? $this->getMapper(Banco::class)->fetchById($row['banco']) : null; + $model->tipo = $this->getMapper(TipoPago::class)->fetchById($row['tipo']); + $model->identificador = $row['identificador']; + $model->fecha = new \DateTimeImmutable($row['fecha']); + $model->uf = $row['uf']; + $model->pagador = $row['pagador']; + $model->asociado = ($row['asociado']) ? $this->fetchById($row['asociado']) : null; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/Pie.php b/src/Mapper/Pie.php new file mode 100644 index 0000000..5e2544c --- /dev/null +++ b/src/Mapper/Pie.php @@ -0,0 +1,23 @@ +id = $row['id']; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/Precio.php b/src/Mapper/Precio.php new file mode 100644 index 0000000..8a22d8c --- /dev/null +++ b/src/Mapper/Precio.php @@ -0,0 +1,43 @@ +id = $row['id']; + $model->valor = $row['valor']; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } + + public function fetchByUnidad(int $unidad_id): array + { + $qb = $this->connection->createQueryBuilder() + ->select('*') + ->from($this->table) + ->where('unidad = ?'); + return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$unidad_id])->fetchAllAssociative()); + } + public function fetchLastByUnidad(int $unidad_id): PrecioModel|bool + { + $qb = $this->connection->createQueryBuilder() + ->select('*') + ->from($this->table) + ->where('unidad = ?') + ->orderBy('id', 'desc') + ->setMaxResults(1); + return $this->load($this->connection->executeQuery($qb, [$unidad_id])->fetchAssociative()); + } +} diff --git a/src/Mapper/Promocion.php b/src/Mapper/Promocion.php new file mode 100644 index 0000000..1804c26 --- /dev/null +++ b/src/Mapper/Promocion.php @@ -0,0 +1,22 @@ +id = $row['id']; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/Propiedad.php b/src/Mapper/Propiedad.php new file mode 100644 index 0000000..d66f45a --- /dev/null +++ b/src/Mapper/Propiedad.php @@ -0,0 +1,24 @@ +id = $row['id']; + $propiedad->estado = $row['estado'] != 0; + $propiedad->unidades = $this->getMapper(Unidad::class)->fetchByPropiedad($row['id']); + return $propiedad; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/Propietario.php b/src/Mapper/Propietario.php new file mode 100644 index 0000000..911238a --- /dev/null +++ b/src/Mapper/Propietario.php @@ -0,0 +1,36 @@ +rut = $row['rut']; + $model->nombres = $row['nombres']; + $model->setApellidos($row['apellido_paterno'], $row['apellido_materno']); + $datos = new PropietarioModel\Datos(); + $datos->sexo = $row['sexo']; + $datos->estado_civil = $row['estado_civil']; + $datos->profesion = $row['profesion']; + $datos->direccion = $row['direccion'] == 0 ? $this->getMapper(Direccion::class)->fetchById($row['direccion']) : 0; + $datos->telefono = $row['telefono']; + $datos->email = $row['email']; + $model->datos = $datos; + $model->repesentante = $row['representante']; + $model->otro = $row['otro']; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/Proyecto.php b/src/Mapper/Proyecto.php new file mode 100644 index 0000000..c05c886 --- /dev/null +++ b/src/Mapper/Proyecto.php @@ -0,0 +1,35 @@ +id = $row['id']; + $model->inmobiliaria = $this->getMapper(Inmobiliaria::class)->fetchById($row['inmobiliaria']); + $model->descripcion = $row['descripcion']; + $model->direccion = $this->getMapper(Direccion::class)->fetchById($row['direccion']); + $model->valor_terreno = $row['valor_terreno']; + $superficie = new ProyectoModel\Superficie(); + $superficie->terreno = $row['superficie_terreno']; + $superficie->bajo_nivel = $row['superficie_bajo_nivel']; + $superficie->sobre_nivel = $row['superficie_sobre_nivel']; + $model->superficie = $superficie; + $model->corredor = $row['corredor']; + $model->pisos = $row['pisos']; + $model->subterraneos = $row['subterraneos']; + return $model; + } + + public function save(Model $model): bool + { + return true; + } +} diff --git a/src/Mapper/ProyectoAgente.php b/src/Mapper/ProyectoAgente.php new file mode 100644 index 0000000..70a0a11 --- /dev/null +++ b/src/Mapper/ProyectoAgente.php @@ -0,0 +1,26 @@ +id = $row['id']; + $model->proyecto = $this->getMapper(Proyecto::class)->fetchById($row['proyecto']); + $model->agenteTipo = $this->getMapper(AgenteTipo::class)->fetchById($row['agente']); + $model->fecha = new \DateTimeImmutable($row['fecha']); + $model->comision = $row['comision']; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/ProyectoTipoUnidad.php b/src/Mapper/ProyectoTipoUnidad.php new file mode 100644 index 0000000..10a953b --- /dev/null +++ b/src/Mapper/ProyectoTipoUnidad.php @@ -0,0 +1,43 @@ +id = $row['id']; + $model->proyecto = $this->getMapper(Proyecto::class)->fetchById($row['proyecto']); + $model->tipo = $this->getMapper(TipoUnidad::class)->fetchById($row['tipo']); + $model->abreviacion = $row['abreviacion']; + $model->nombre = $row['nombre']; + $supreficie = new TipoModel\Superficie(); + $supreficie->interior = $row['m2']; + $supreficie->logia = $row['logia']; + $supreficie->terraza = $row['terraza']; + $model->superficie = $supreficie; + $model->descripcion = $row['descripcion']; + $model->tipologias = $this->getMapper(TipoTipologia::class)->fetchByPTU($row['id']); + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } + + public function fetchByProyecto(int $proyecto_id): array + { + $qb = $this->connection->createQueryBuilder() + ->select('*') + ->from($this->table) + ->where('proyecto = ?'); + return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$proyecto_id])->fetchAllAssociative()); + } +} diff --git a/src/Mapper/Subsidio.php b/src/Mapper/Subsidio.php new file mode 100644 index 0000000..670ef64 --- /dev/null +++ b/src/Mapper/Subsidio.php @@ -0,0 +1,22 @@ +id = $row['id']; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/TipoElemento.php b/src/Mapper/TipoElemento.php new file mode 100644 index 0000000..42e8c26 --- /dev/null +++ b/src/Mapper/TipoElemento.php @@ -0,0 +1,26 @@ +id = $row['id']; + $model->descripcion = $row['descripcion']; + $model->abreviacion = $row['abreviacion']; + $model->orden = $row['orden']; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/TipoEstadoCierre.php b/src/Mapper/TipoEstadoCierre.php new file mode 100644 index 0000000..b96336c --- /dev/null +++ b/src/Mapper/TipoEstadoCierre.php @@ -0,0 +1,25 @@ +id = $row['id']; + $model->descripcion = $row['descripcion']; + $model->vigente = $row['vigente'] !== 0; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/TipoEstadoPrecio.php b/src/Mapper/TipoEstadoPrecio.php new file mode 100644 index 0000000..819cfcc --- /dev/null +++ b/src/Mapper/TipoEstadoPrecio.php @@ -0,0 +1,24 @@ +id = $row['id']; + $model->descripcion = $row['descripcion']; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/TipoEstadoVenta.php b/src/Mapper/TipoEstadoVenta.php new file mode 100644 index 0000000..dc61cd0 --- /dev/null +++ b/src/Mapper/TipoEstadoVenta.php @@ -0,0 +1,24 @@ +id = $row['id']; + $model->descripcion = $row['descripcion']; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/TipoPago.php b/src/Mapper/TipoPago.php new file mode 100644 index 0000000..28c163a --- /dev/null +++ b/src/Mapper/TipoPago.php @@ -0,0 +1,23 @@ +id = $row['id']; + $model->tipologia = $this->getMapper(Tipologia::class)->fetchById($row['tipologia']); + $model->cantidad = $row['cantidad']; + $model->elemento = $this->getMapper(TipoElemento::class)->fetchById($row['elemento']); + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } + + public function fetchByPTU(int $ptu_id): array + { + $qb = $this->connection->createQueryBuilder() + ->select('tt.*') + ->from($this->table, 'tt') + ->innerJoin('tt', 'tipo_elemento', 'te', 'te.id = tt.elemento') + ->where('tt.tipo = ?') + ->orderBy('te.orden'); + return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$ptu_id])->fetchAllAssociative()); + } +} diff --git a/src/Mapper/TipoUnidad.php b/src/Mapper/TipoUnidad.php new file mode 100644 index 0000000..080456c --- /dev/null +++ b/src/Mapper/TipoUnidad.php @@ -0,0 +1,25 @@ +id = $row['id']; + $model->descripcion = $row['descripcion']; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/Tipologia.php b/src/Mapper/Tipologia.php new file mode 100644 index 0000000..efc39e1 --- /dev/null +++ b/src/Mapper/Tipologia.php @@ -0,0 +1,24 @@ +id = $row['id']; + $model->descripcion = $row['descripcion']; + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } +} diff --git a/src/Mapper/Unidad.php b/src/Mapper/Unidad.php new file mode 100644 index 0000000..fc1a46d --- /dev/null +++ b/src/Mapper/Unidad.php @@ -0,0 +1,46 @@ +id = $row['id']; + $model->subtipo = $row['subtipo']; + $model->piso = $row['piso']; + $model->descripcion = $row['descripcion']; + $model->abreviacion = $row['abreviacion']; + $model->orientacion = $row['orientacion']; + $model->proyectoTipoUnidad = $this->getMapper(ProyectoTipoUnidad::class)->fetchById($row['pt']); + return $model; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } + + public function fetchByTipo(int $tipo_id): array + { + $qb = $this->connection->createQueryBuilder() + ->select('*') + ->from($this->table) + ->where('pt = ?'); + return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$tipo_id])->fetchAllAssociative()); + } + public function fetchByPropiedad(int $propiedad_id): array + { + $qb = $this->connection->createQueryBuilder() + ->select('u.*') + ->from($this->table, 'u') + ->innerJoin('u', 'propiedad_unidad', 'pu', 'pu.unidad = u.id') + ->where('pu.propiedad = ?'); + return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$propiedad_id])->fetchAllAssociative()); + } +} diff --git a/src/Mapper/User.php b/src/Mapper/User.php new file mode 100644 index 0000000..91f4cb7 --- /dev/null +++ b/src/Mapper/User.php @@ -0,0 +1,54 @@ +id = $row['id']; + $model->name = $row['name']; + $model->setPassword($row['password']); + $model->enabled = $row['enabled'] != 0; + return $model; + } + public function save(Model $model): bool + { + if (isset($model->id)) { + $qb = $this->connection->createQueryBuilder() + ->insert($this->table) + ->values([ + 'name' => $model->name, + 'password' => $model->getPassword(), + 'enabled' => $model->enabled ? 1 : 0 + ]); + return $this->connection->executeStatement($qb) > 0; + } + $qb = $this->connection->createQueryBuilder() + ->update($this->table) + ->set('name', $model->name) + ->set('password', $model->getPassword()) + ->set('enabled', $model->enabled ? 1 : 0) + ->where('id = ?'); + return $this->connection->executeStatement($qb, [$model->id]) > 0; + } + + public function fetchByName(string $name): UserModel|bool + { + $qb = $this->connection->createQueryBuilder() + ->select('*') + ->from($this->table) + ->where('name = ?'); + return $this->load( + $this->connection + ->executeQuery($qb, [$name]) + ->fetchAssociative() + ); + } +} diff --git a/src/Mapper/Venta.php b/src/Mapper/Venta.php new file mode 100644 index 0000000..aadc1c5 --- /dev/null +++ b/src/Mapper/Venta.php @@ -0,0 +1,97 @@ +id = $row['id']; + $venta->propietario = $this->getMapper(Propietario::class)->fetchById($row['propietario']); + $venta->propiedad = $this->getMapper(Propiedad::class)->fetchById($row['propiedad']); + $venta->fecha = new \DateTimeImmutable($row['fecha']); + $venta->valor = $row['valor_uf']; + $venta->estado = $row['estado']; + $venta->fecha_ingreso = new \DateTimeImmutable($row['fecha_ingreso']); + $venta->uf = $row['uf']; + $forma_pago = new VentaModel\FormaPago(); + $forma_pago->pie = $row['pie'] ? $this->getMapper(Pie::class)->fetchById($row['pie']) : null; + $forma_pago->bonoPie = $row['bono_pie'] ? $this->getMapper(BonoPie::class)->fetchById($row['bono_pie']) : null; + $forma_pago->escritura = $row['escritura'] ? $this->getMapper(Escritura::class)->fetchById($row['escritura']) : null; + $forma_pago->credito = $row['credito'] ? $this->getMapper(Credito::class)->fetchById($row['credito']) : null; + $forma_pago->subsidio = $row['subsidio'] ? $this->getMapper(Subsidio::class)->fetchById($row['subsidio']) : null; + $venta->formaPago = $forma_pago; + $estado = new VentaModel\Estado(); + $estado->escriturado = $row['escriturado'] ? new \DateTimeImmutable($row['escriturado']) : null; + $estado->entrega = $row['entrega'] ? $this->getMapper(Entrega::class)->fetchById($row['entrega']) : null; + $estado->entregado = $row['entregado'] ? new \DateTimeImmutable($row['entregado']) : null; + $venta->estado_venta = $estado; + $datos = new VentaModel\Datos(); + $datos->avalchile = $row['avalchile'] != 0; + $datos->agente = $row['agente'] ? $this->getMapper(ProyectoAgente::class)->fetchById($row['agente']) : null; + $datos->relacionado = $row['relacionado'] != 0; + $datos->promocion = $row['promocion'] ? $this->getMapper(Promocion::class)->fetchById($row['promocion']) : null; + $datos->resciliacion = $row['resciliacion'] ? $this->getMapper(Pago::class)->fetchById($row['resciliacion']) : null; + $datos->devolucion = $row['devolucion'] ? $this->getMapper(Pago::class)->fetchById($row['devolucion']) : null; + $venta->datos = $datos; + $venta->setFactory($this->factory); + return $venta; + } + + public function save(Model $model): bool + { + // TODO: Implement save() method. + } + + public function fetchByProyecto(int $proyecto_id): array + { + $qb = $this->connection->createQueryBuilder(); + $qb->select('a.*') + ->from($this->table, 'a') + ->innerJoin('a', 'propiedad', 'p', 'p.id = a.propiedad') + ->innerJoin('p', 'unidad', 'u', 'u.id = p.unidad_principal') + ->innerJoin('u', 'proyecto', 'o', 'o.id = u.proyecto') + ->where("o.id = ?") + ->orderBy("LPAD(u.descripcion, 4, '0')"); + $row = $this->connection->executeQuery($qb, [$proyecto_id])->fetchAllAssociative(); + return array_map([$this, 'load'], $row); + } + public function fetchActivaByProyecto(int $proyecto_id): array + { + $qb = $this->connection->createQueryBuilder(); + $qb->select('v.*') + ->from($this->table, 'v') + ->innerJoin('v', 'propiedad', 'p', 'p.id = v.propiedad') + ->innerJoin('p', 'unidad', 'u', 'u.id = p.unidad_principal') + ->innerJoin('u', 'proyecto', 'o', 'o.id = u.proyecto') + ->innerJoin('v', '(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', 'ev.venta = v.id') + ->innerJoin('ev', 'tipo_estado_venta', 'tev', 'tev.id = ev.estado') + ->where("o.id = ?") + ->andWhere('tev.activa = 1') + ->orderBy("LPAD(u.descripcion, 4, '0')"); + $row = $this->connection->executeQuery($qb, [$proyecto_id])->fetchAllAssociative(); + return array_map([$this, 'load'], $row); + } + public function fetchCountByProyecto(int $proyecto_id): int|bool + { + $qb = $this->connection->createQueryBuilder(); + $qb->select("COUNT(v.id) AS 'cantidad'") + ->from($this->table, 'v') + ->innerJoin('v', 'propiedad', 'p', 'p.id = v.propiedad') + ->innerJoin('p', 'unidad', 'u', 'u.id = p.unidad_principal') + ->innerJoin('u', 'proyecto', 'o', 'o.id = u.proyecto') + ->innerJoin('v', '(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', 'ev.venta = v.id') + ->innerJoin('ev', 'tipo_estado_venta', 'tev', 'tev.id = ev.estado') + ->where("o.id = ?") + ->andWhere('tev.activa = 1') + ->groupBy('o.id'); + $row = $this->connection->executeQuery($qb, [$proyecto_id])->fetchAssociative(); + return $row ? $row['cantidad'] : false; + } +} diff --git a/src/Model/Admin/Config.php b/src/Model/Admin/Config.php new file mode 100644 index 0000000..76db1e2 --- /dev/null +++ b/src/Model/Admin/Config.php @@ -0,0 +1,9 @@ +password = $password; + return $this; + } + public function getPassword(): string + { + return $this->password; + } + public function validate($password): bool { + return password_verify($password, $this->password); + } +} diff --git a/src/Model/Common/Banco.php b/src/Model/Common/Banco.php new file mode 100644 index 0000000..9af896f --- /dev/null +++ b/src/Model/Common/Banco.php @@ -0,0 +1,17 @@ + $this->id, + 'nombre' => $this->nombre + ]; + } +} diff --git a/src/Model/Common/Comuna.php b/src/Model/Common/Comuna.php new file mode 100644 index 0000000..748f307 --- /dev/null +++ b/src/Model/Common/Comuna.php @@ -0,0 +1,8 @@ +factory = $factory; + return $this; + } + public function getMapper(string $name): Mapper + { + if (!class_exists($name)) { + throw new \InvalidArgumentException("Mapper {$name} not found."); + } + if (!isset($this->mappers)) { + $this->mappers = []; + } + if (!isset($this->mappers[$name])) { + $this->mappers[$name] = $this->factory->get($name); + } + return $this->mappers[$name]; + } + + public function jsonSerialize(): mixed + { + return (array) $this; + } +} diff --git a/src/Model/Proyecto/AgenteTipo.php b/src/Model/Proyecto/AgenteTipo.php new file mode 100644 index 0000000..d895f87 --- /dev/null +++ b/src/Model/Proyecto/AgenteTipo.php @@ -0,0 +1,9 @@ + $this->terreno, + 'sobre_nivel' => $this->sobre_nivel, + 'bajo_nivel' => $this->bajo_nivel + ]; + } +} diff --git a/src/Model/Proyecto/ProyectoAgente.php b/src/Model/Proyecto/ProyectoAgente.php new file mode 100644 index 0000000..99200df --- /dev/null +++ b/src/Model/Proyecto/ProyectoAgente.php @@ -0,0 +1,12 @@ + implode('/', array_map(function($tt) { + if (str_contains($tt->elemento->descripcion, 'cocina')) { + return $tt->elemento->abreviacion; + } + return $tt->cantidad . $tt->elemento->abreviacion; + }, $this->tipologias)), + 'detalle' => implode(', ', array_map(function ($tt) { + if (str_contains($tt->elemento->descripcion, 'cocina')) { + return $tt->elemento->descripcion; + } + return $tt->cantidad . ' ' . $tt->elemento->descripcion . (($tt->cantidad > 0) ? 's' : ''); + }, $this->tipologias)) + ]; + return $arr; + } +} diff --git a/src/Model/Proyecto/ProyectoTipoUnidad/Superficie.php b/src/Model/Proyecto/ProyectoTipoUnidad/Superficie.php new file mode 100644 index 0000000..2bd9b38 --- /dev/null +++ b/src/Model/Proyecto/ProyectoTipoUnidad/Superficie.php @@ -0,0 +1,24 @@ +interior + $this->logia + $this->terraza / 2; + } + + public function jsonSerialize(): array + { + return [ + 'interior' => $this->interior, + 'logia' => $this->logia, + 'terraza' => $this->terraza, + 'vendible' => $this->vendible() + ]; + } +} diff --git a/src/Model/Proyecto/TipoElemento.php b/src/Model/Proyecto/TipoElemento.php new file mode 100644 index 0000000..8c809b9 --- /dev/null +++ b/src/Model/Proyecto/TipoElemento.php @@ -0,0 +1,11 @@ +proyectoTipoUnidad->proyecto->jsonSerialize(); + $arr['tipo'] = $this->proyectoTipoUnidad->tipo->jsonSerialize(); + $arr['superficie'] = $this->proyectoTipoUnidad->superficie->jsonSerialize(); + return $arr; + } +} diff --git a/src/Model/Venta/BonoPie.php b/src/Model/Venta/BonoPie.php new file mode 100644 index 0000000..a618c03 --- /dev/null +++ b/src/Model/Venta/BonoPie.php @@ -0,0 +1,10 @@ +estadoCierre)) { + $this->estadoCierre = $this->mappers[EstadoMapper::class]->fetchLastByCierre($this->id); + } + return $this->estadoCierre; + } +} diff --git a/src/Model/Venta/Credito.php b/src/Model/Venta/Credito.php new file mode 100644 index 0000000..c38dc20 --- /dev/null +++ b/src/Model/Venta/Credito.php @@ -0,0 +1,8 @@ + '', 'materno' => '']; + public Datos $datos; + public int $repesentante; + public int $otro; + + public function setApellidos(string $paterno, string $materno): Propietario + { + $this->apellidos['paterno'] = $paterno; + $this->apellidos['materno'] = $materno; + return $this; + } + public function getApellido($tipo): string + { + return $this->apellidos[$tipo]; + } + public function nombreCompleto(): string + { + return implode(' ', [ + $this->nombres, + implode(' ', $this->apellidos) + ]); + } + + public function jsonSerialize(): array + { + $arr = parent::jsonSerialize(); + $arr['nombreCompleto'] = $this->nombreCompleto(); + return $arr; + } +} diff --git a/src/Model/Venta/Propietario/Datos.php b/src/Model/Venta/Propietario/Datos.php new file mode 100644 index 0000000..0b590cc --- /dev/null +++ b/src/Model/Venta/Propietario/Datos.php @@ -0,0 +1,14 @@ +