diff --git a/app/common/Alias/View.php b/app/common/Alias/View.php new file mode 100644 index 0000000..80df0a9 --- /dev/null +++ b/app/common/Alias/View.php @@ -0,0 +1,9 @@ + $this->id + ]; + } +} diff --git a/app/common/Ideal/Repository.php b/app/common/Ideal/Repository.php new file mode 100644 index 0000000..9b4acc7 --- /dev/null +++ b/app/common/Ideal/Repository.php @@ -0,0 +1,126 @@ +table; + } + public function setTable(string $table): Repository + { + $this->table = $table; + return $this; + } + + public function load(array $data_row): Model + { + $model = $this->create($data_row); + $model->{$this->getKey()} = $data_row[$this->getKey()]; + return $model; + } + + public function remove(Model $model): void + { + $query = "DELETE FROM `{$this->getTable()}` WHERE `{$this->getKey()}` = ?"; + $this->connection->execute($query, [$model->getId()]); + } + + public function fetchById(int $id): Define\Model + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `{$this->getKey()}` = ?"; + return $this->fetchOne($query, [$id]); + } + public function fetchAll(): array + { + $query = "SELECT * FROM `{$this->getTable()}`"; + return $this->fetchMany($query); + } + + protected function getKey(): string + { + return 'id'; + } + protected function parseData(Define\Model $model, ?array $data, array $data_map): Define\Model + { + if ($data === null) { + return $model; + } + foreach ($data_map as $column => $settings) { + if (isset($data[$column])) { + $property = $column; + if (isset($settings['property'])) { + $property = $settings['property']; + } + $value = $data[$column]; + if (isset($settings['function'])) { + $value = $settings['function']($data); + } + $model->{$property} = $value; + } + } + return $model; + } + protected function saveNew(array $columns, array $values): int + { + $columns_string = implode(', ', array_map(function($column) {return "`{$column}`";}, $columns)); + $columns_questions = implode(', ', array_fill(0, count($columns), '?')); + $query = "INSERT INTO `{$this->getTable()}` ({$columns_string}) VALUES ($columns_questions)"; + $this->connection->execute($query, $values); + return $this->connection->getPDO()->lastInsertId(); + } + protected function update(Model $model, array $columns, array $data): Define\Model + { + $changes = []; + $values = []; + foreach ($columns as $column) { + if (isset($data[$column])) { + $changes []= $column; + $values []= $data[$column]; + } + } + if (count($changes) === 0) { + return $model; + } + $columns_string = implode(', ', array_map(function($property) {return "`{$property}` = ?";}, $changes)); + $query = "UPDATE `{$this->getTable()}` SET {$columns_string} WHERE `{$this->getKey()}` = ?"; + $values []= $model->id; + $this->connection->execute($query, $values); + $id = $model->id; + $model = $this->create($data); + $model->id = $id; + return $model; + } + protected function fetchOne(string $query, ?array $data = null): Define\Model + { + $result = $this->connection->execute($query, $data)->fetch(PDO::FETCH_ASSOC); + if ($result === false) { + throw new EmptyResult($query); + } + return $this->load($result); + } + protected function fetchMany(string $query, ?array $data = null): array + { + $results = $this->connection->execute($query, $data)->fetchAll(PDO::FETCH_ASSOC); + if ($results === false) { + throw new EmptyResult($query); + } + return array_map([$this, 'load'], $results); + } + protected function fetchAsArray(string $query, ?array $data = null): array + { + $results = $this->connection->execute($query, $data)->fetchAll(PDO::FETCH_ASSOC); + if ($results === false) { + throw new EmptyResult($query); + } + return $results; + } +} diff --git a/app/common/Implement/Connection.php b/app/common/Implement/Connection.php new file mode 100644 index 0000000..bcb6eab --- /dev/null +++ b/app/common/Implement/Connection.php @@ -0,0 +1,61 @@ +connection)) { + if ($this->database->needsUser()) { + $this->connection = new PDO($this->database->getDSN(), $this->database->user, $this->database->password); + } else { + $this->connection = new PDO($this->database->getDSN()); + } + } + return $this; + } + public function getPDO(): PDO + { + $this->connect(); + return $this->connection; + } + + public function query(string $query): PDOStatement + { + $this->connect(); + $statement = $this->connection->query($query); + if ($statement === false) { + throw new PDOException("Query failed: '{$query}'"); + } + return $statement; + } + public function prepare(string $query): PDOStatement + { + $this->connect(); + $statement = $this->connection->prepare($query); + if ($statement === false) { + throw new PDOException("Query failed: '{$query}'"); + } + return $statement; + } + public function execute(string $query, ?array $data = null): PDOStatement + { + if ($data === null) { + return $this->query($query); + } + $statement = $this->prepare($query); + $status = $statement->execute($data); + if ($status === false) { + throw new PDOException("Query could not be executed: '{$query}'"); + } + return $statement; + } +} diff --git a/app/common/Implement/Database/MySQL.php b/app/common/Implement/Database/MySQL.php new file mode 100644 index 0000000..b2bca28 --- /dev/null +++ b/app/common/Implement/Database/MySQL.php @@ -0,0 +1,24 @@ +host};dbname={$this->name}"; + if ($this->port !== 3306) { + $dsn .= ";port={$this->port}"; + } + return $dsn; + } + public function needsUser(): bool + { + return true; + } +} diff --git a/app/common/Implement/Exception/EmptyResult.php b/app/common/Implement/Exception/EmptyResult.php new file mode 100644 index 0000000..2a8e3ef --- /dev/null +++ b/app/common/Implement/Exception/EmptyResult.php @@ -0,0 +1,15 @@ +run(); diff --git a/app/public/robots.txt b/app/public/robots.txt new file mode 100644 index 0000000..1f53798 --- /dev/null +++ b/app/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / diff --git a/app/resources/routes/01_api.php b/app/resources/routes/01_api.php new file mode 100644 index 0000000..a8f19fa --- /dev/null +++ b/app/resources/routes/01_api.php @@ -0,0 +1,13 @@ +group('/api', function($app) { + $folder = implode(DIRECTORY_SEPARATOR, [__DIR__, 'api']); + if (file_exists($folder)) { + $files = new FilesystemIterator($folder); + foreach ($files as $file) { + if ($file->isDir()) { + continue; + } + include_once $file->getRealPath(); + } + } +}); diff --git a/app/resources/routes/03_proyectos.php b/app/resources/routes/03_proyectos.php new file mode 100644 index 0000000..02303aa --- /dev/null +++ b/app/resources/routes/03_proyectos.php @@ -0,0 +1,6 @@ +group('/proyectos', function($app) { + $app->get('[/]', Proyectos::class); +}); diff --git a/app/resources/routes/04_ventas.php b/app/resources/routes/04_ventas.php new file mode 100644 index 0000000..93a94c7 --- /dev/null +++ b/app/resources/routes/04_ventas.php @@ -0,0 +1,10 @@ +group('/ventas', function($app) { + $files = new FilesystemIterator(implode(DIRECTORY_SEPARATOR, [__DIR__, 'ventas'])); + foreach ($files as $file) { + if ($file->isDir()) { + continue; + } + include_once $file->getRealPath(); + } +}); diff --git a/app/resources/routes/98_login.php b/app/resources/routes/98_login.php new file mode 100644 index 0000000..4521062 --- /dev/null +++ b/app/resources/routes/98_login.php @@ -0,0 +1,8 @@ +group('/login', function($app) { + $app->post('[/]', [Login::class, 'login']); + $app->get('[/]', [Login::class, 'form']); +}); +$app->get('/logout', [Login::class, 'logout']); diff --git a/app/resources/routes/99_base.php b/app/resources/routes/99_base.php new file mode 100644 index 0000000..c8c764e --- /dev/null +++ b/app/resources/routes/99_base.php @@ -0,0 +1,4 @@ +get('[/]', Base::class); diff --git a/app/resources/routes/api/proyectos.php b/app/resources/routes/api/proyectos.php new file mode 100644 index 0000000..a0bf995 --- /dev/null +++ b/app/resources/routes/api/proyectos.php @@ -0,0 +1,6 @@ +group('/proyectos', function($app) { + $app->get('[/]', [Proyectos::class, 'list']); +}); diff --git a/app/resources/routes/api/ventas.php b/app/resources/routes/api/ventas.php new file mode 100644 index 0000000..361f498 --- /dev/null +++ b/app/resources/routes/api/ventas.php @@ -0,0 +1,13 @@ +group('/ventas', function($app) { + $folder = implode(DIRECTORY_SEPARATOR, [__DIR__, 'ventas']); + if (file_exists($folder)) { + $files = new FilesystemIterator($folder); + foreach ($files as $file) { + if ($file->isDir()) { + continue; + } + include_once $file->getRealPath(); + } + } +}); diff --git a/app/resources/routes/api/ventas/precios.php b/app/resources/routes/api/ventas/precios.php new file mode 100644 index 0000000..0ad9ba4 --- /dev/null +++ b/app/resources/routes/api/ventas/precios.php @@ -0,0 +1,6 @@ +group('/precios', function($app) { + $app->post('[/]', [Precios::class, 'proyecto']); +}); diff --git a/app/resources/routes/ventas/cuotas.php b/app/resources/routes/ventas/cuotas.php new file mode 100644 index 0000000..981dccd --- /dev/null +++ b/app/resources/routes/ventas/cuotas.php @@ -0,0 +1,9 @@ +group('/cuotas', function($app) { + $app->get('/pendientes[/]', [Cuotas::class, 'pendientes']); +}); +$app->group('/cuota', function($app) { + $app->post('/depositar[/]', [Cuotas::class, 'depositar']); +}); diff --git a/app/resources/routes/ventas/precios.php b/app/resources/routes/ventas/precios.php new file mode 100644 index 0000000..c035216 --- /dev/null +++ b/app/resources/routes/ventas/precios.php @@ -0,0 +1,6 @@ +group('/precios', function($app) { + $app->get('[/]', Precios::class); +}); diff --git a/app/resources/views/guest.blade.php b/app/resources/views/guest.blade.php new file mode 100644 index 0000000..8acdfe6 --- /dev/null +++ b/app/resources/views/guest.blade.php @@ -0,0 +1,7 @@ +@extends('layout.base') + +@section('page_content') +
+ Bienvenid@ a Incoviba +
+@endsection diff --git a/app/resources/views/home.blade.php b/app/resources/views/home.blade.php new file mode 100644 index 0000000..06597bf --- /dev/null +++ b/app/resources/views/home.blade.php @@ -0,0 +1,26 @@ +@extends('layout.base') + +@section('page_content') +
+

Bienvenid@ {{$user->name}}

+
+ @if ($cuotas_hoy > 0) + Existe{{$cuotas_hoy > 1 ? 'n' : ''}} {{$cuotas_hoy}} deposito{{$cuotas_hoy > 1 ? 's' : ''}} para hoy. +
+ @endif + @if ($cuotas_pendientes > 0) + + Existe{{$cuotas_pendientes > 1 ? 'n' : ''}} {{$cuotas_pendientes}} cuota{{$cuotas_pendientes > 1 ? 's' : ''}} pendiente{{$cuotas_pendientes > 1 ? 's' : ''}}. + + @endif +
+
+
+ @include('home.cuotas_por_vencer') +
+
+ @include('home.cierres_vigentes') +
+
+
+@endsection diff --git a/app/resources/views/home/cierres_vigentes.blade.php b/app/resources/views/home/cierres_vigentes.blade.php new file mode 100644 index 0000000..fe974e0 --- /dev/null +++ b/app/resources/views/home/cierres_vigentes.blade.php @@ -0,0 +1,24 @@ +

Cierres Vigentes

+
+ @foreach($cierres_vigentes as $proyecto => $estados) +
+
+
+ {{$proyecto}} [{{$estados['total']}}] +
+
+
Promesados
+
{{$estados['promesados']}}
+
+
+
Pendientes
+
{{$estados['pendientes']}}
+
+
+
Rechazados
+
{{$estados['rechazados']}}
+
+
+
+ @endforeach +
diff --git a/app/resources/views/home/cuotas_por_vencer.blade.php b/app/resources/views/home/cuotas_por_vencer.blade.php new file mode 100644 index 0000000..a0df444 --- /dev/null +++ b/app/resources/views/home/cuotas_por_vencer.blade.php @@ -0,0 +1,22 @@ +

Cuotas Por Vencer

+
+ @foreach ($cuotas_por_vencer as $date => $proyectos) +
+
+
+ {{$format->localDate($date, "EEE. dd 'de' MMMM 'de' yyyy", true)}} +
+ @foreach ($proyectos as $proyecto => $cuotas) +
+
+ + {{$proyecto}} + +
+
{{$cuotas}}
+
+ @endforeach +
+
+ @endforeach +
diff --git a/app/resources/views/layout/base.blade.php b/app/resources/views/layout/base.blade.php new file mode 100644 index 0000000..9deb8c1 --- /dev/null +++ b/app/resources/views/layout/base.blade.php @@ -0,0 +1,5 @@ + + +@include('layout.head') +@include('layout.body') + diff --git a/app/resources/views/layout/body.blade.php b/app/resources/views/layout/body.blade.php new file mode 100644 index 0000000..fb0cc48 --- /dev/null +++ b/app/resources/views/layout/body.blade.php @@ -0,0 +1,5 @@ + + @include('layout.body.header') + @yield('page_content') + @include('layout.body.footer') + diff --git a/app/resources/views/layout/body/footer.blade.php b/app/resources/views/layout/body/footer.blade.php new file mode 100644 index 0000000..c3b1007 --- /dev/null +++ b/app/resources/views/layout/body/footer.blade.php @@ -0,0 +1,4 @@ + +@include('layout.body.scripts') diff --git a/app/resources/views/layout/body/header.blade.php b/app/resources/views/layout/body/header.blade.php new file mode 100644 index 0000000..48d779d --- /dev/null +++ b/app/resources/views/layout/body/header.blade.php @@ -0,0 +1,7 @@ +
+ + logo + + @include('layout.body.header.menu') +
+
diff --git a/app/resources/views/layout/body/header/menu.blade.php b/app/resources/views/layout/body/header/menu.blade.php new file mode 100644 index 0000000..392dc36 --- /dev/null +++ b/app/resources/views/layout/body/header/menu.blade.php @@ -0,0 +1,17 @@ + diff --git a/app/resources/views/layout/body/header/menu/contabilidad.blade.php b/app/resources/views/layout/body/header/menu/contabilidad.blade.php new file mode 100644 index 0000000..7ed6b0c --- /dev/null +++ b/app/resources/views/layout/body/header/menu/contabilidad.blade.php @@ -0,0 +1,8 @@ + diff --git a/app/resources/views/layout/body/header/menu/guest.blade.php b/app/resources/views/layout/body/header/menu/guest.blade.php new file mode 100644 index 0000000..8c7399b --- /dev/null +++ b/app/resources/views/layout/body/header/menu/guest.blade.php @@ -0,0 +1 @@ +Ingresar diff --git a/app/resources/views/layout/body/header/menu/herramientas.blade.php b/app/resources/views/layout/body/header/menu/herramientas.blade.php new file mode 100644 index 0000000..45b0b52 --- /dev/null +++ b/app/resources/views/layout/body/header/menu/herramientas.blade.php @@ -0,0 +1,7 @@ + diff --git a/app/resources/views/layout/body/header/menu/inmobiliarias.blade.php b/app/resources/views/layout/body/header/menu/inmobiliarias.blade.php new file mode 100644 index 0000000..9aa161c --- /dev/null +++ b/app/resources/views/layout/body/header/menu/inmobiliarias.blade.php @@ -0,0 +1 @@ +Inmobiliarias diff --git a/app/resources/views/layout/body/header/menu/operadores.blade.php b/app/resources/views/layout/body/header/menu/operadores.blade.php new file mode 100644 index 0000000..c30b9c0 --- /dev/null +++ b/app/resources/views/layout/body/header/menu/operadores.blade.php @@ -0,0 +1,9 @@ + diff --git a/app/resources/views/layout/body/header/menu/proyectos.blade.php b/app/resources/views/layout/body/header/menu/proyectos.blade.php new file mode 100644 index 0000000..c72eb69 --- /dev/null +++ b/app/resources/views/layout/body/header/menu/proyectos.blade.php @@ -0,0 +1,8 @@ + diff --git a/app/resources/views/layout/body/header/menu/search.blade.php b/app/resources/views/layout/body/header/menu/search.blade.php new file mode 100644 index 0000000..cd4315e --- /dev/null +++ b/app/resources/views/layout/body/header/menu/search.blade.php @@ -0,0 +1 @@ + diff --git a/app/resources/views/layout/body/header/menu/user.blade.php b/app/resources/views/layout/body/header/menu/user.blade.php new file mode 100644 index 0000000..e2bd013 --- /dev/null +++ b/app/resources/views/layout/body/header/menu/user.blade.php @@ -0,0 +1,31 @@ + + +@push('page_scripts') + +@endpush diff --git a/app/resources/views/layout/body/header/menu/ventas.blade.php b/app/resources/views/layout/body/header/menu/ventas.blade.php new file mode 100644 index 0000000..7d669cc --- /dev/null +++ b/app/resources/views/layout/body/header/menu/ventas.blade.php @@ -0,0 +1,41 @@ + diff --git a/app/resources/views/layout/body/scripts.blade.php b/app/resources/views/layout/body/scripts.blade.php new file mode 100644 index 0000000..9b8faa6 --- /dev/null +++ b/app/resources/views/layout/body/scripts.blade.php @@ -0,0 +1,4 @@ + + + +@stack('page_scripts') diff --git a/app/resources/views/layout/body/scripts/datatables.blade.php b/app/resources/views/layout/body/scripts/datatables.blade.php new file mode 100644 index 0000000..980cdf7 --- /dev/null +++ b/app/resources/views/layout/body/scripts/datatables.blade.php @@ -0,0 +1,4 @@ +@push('page_scripts') + + +@endpush diff --git a/app/resources/views/layout/head.blade.php b/app/resources/views/layout/head.blade.php new file mode 100644 index 0000000..98233b9 --- /dev/null +++ b/app/resources/views/layout/head.blade.php @@ -0,0 +1,10 @@ + + + @hasSection('page_title') + Incoviba - @yield('page_title') + @else + Incoviba + @endif + + @include('layout.head.styles') + diff --git a/app/resources/views/layout/head/styles.blade.php b/app/resources/views/layout/head/styles.blade.php new file mode 100644 index 0000000..60ed4f9 --- /dev/null +++ b/app/resources/views/layout/head/styles.blade.php @@ -0,0 +1,3 @@ + + +@stack('page_styles') diff --git a/app/resources/views/layout/head/styles/datatables.blade.php b/app/resources/views/layout/head/styles/datatables.blade.php new file mode 100644 index 0000000..a5dcca3 --- /dev/null +++ b/app/resources/views/layout/head/styles/datatables.blade.php @@ -0,0 +1,3 @@ +@push('page_styles') + +@endpush diff --git a/app/resources/views/login/form.blade.php b/app/resources/views/login/form.blade.php new file mode 100644 index 0000000..31e38ff --- /dev/null +++ b/app/resources/views/login/form.blade.php @@ -0,0 +1,60 @@ +@extends('layout.base') + +@section('page_content') +
+
+
+ + +
+
+ + +
+ +
+
+@endsection + +@push('page_scripts') + +@endpush diff --git a/app/resources/views/ventas/cuotas/pendientes.blade.php b/app/resources/views/ventas/cuotas/pendientes.blade.php new file mode 100644 index 0000000..00a4ba1 --- /dev/null +++ b/app/resources/views/ventas/cuotas/pendientes.blade.php @@ -0,0 +1,108 @@ +@extends('layout.base') + +@section('page_content') +
+

Cuotas Pendientes

+
+
Total
+
{{count($cuotas_pendientes)}}
+
{{$format->pesos(array_reduce($cuotas_pendientes, function($sum, $cuota) {return $sum + $cuota['Valor'];}, 0))}}
+
+ + + + + + + + + + + + + + + + + + @foreach($cuotas_pendientes as $cuota) + + + + + + + + + + + + + + @endforeach + +
ProyectoDepartamentoDepartamento SortValorDíaCuotaPropietarioBancoFecha Cheque (Días)Fecha ISODepositar
{{$cuota['Proyecto']}} + + {{$cuota['Departamento']}} + + {{str_pad($cuota['Departamento'], 4, '0', STR_PAD_LEFT)}}{{$format->pesos($cuota['Valor'])}}{{$cuota['Dia']}}{{$cuota['Numero']}}{{$cuota['Propietario']}}{{$cuota['Banco']}}{{$cuota['Fecha Cheque']}} ({{$cuota['Vencida']}}){{$cuota['Fecha ISO']}} + +
+
+@endsection + +@include('layout.head.styles.datatables') +@include('layout.body.scripts.datatables') + +@push('page_scripts') + +@endpush diff --git a/app/resources/views/ventas/precios/list.blade.php b/app/resources/views/ventas/precios/list.blade.php new file mode 100644 index 0000000..101e4de --- /dev/null +++ b/app/resources/views/ventas/precios/list.blade.php @@ -0,0 +1,676 @@ +@extends('layout.base') + + +@section('page_title') + Precios - Listado +@endsection + +@section('page_content') +
+

Listado de Precios

+
+

+
+
+
+
+ + +
+ +
+
+

+ +
+
+
+ +@endsection + +@push('page_styles') + +@endpush + +@push('page_scripts') + +@endpush diff --git a/app/setup/app.php b/app/setup/app.php new file mode 100644 index 0000000..a17667e --- /dev/null +++ b/app/setup/app.php @@ -0,0 +1,45 @@ +isDir()) { + continue; + } + $builder->addDefinitions($file->getRealPath()); + } + } + $app = Bridge::create($builder->build()); + $folder = implode(DIRECTORY_SEPARATOR, [ + __DIR__, + 'middlewares' + ]); + if (file_exists($folder)) { + $files = new FilesystemIterator($folder); + foreach ($files as $file) { + if ($file->isDir()) { + continue; + } + require_once $file->getRealPath(); + } + } + return $app; +} +return buildApp(); diff --git a/app/setup/composer.php b/app/setup/composer.php new file mode 100644 index 0000000..b451f96 --- /dev/null +++ b/app/setup/composer.php @@ -0,0 +1,6 @@ +add($app->getContainer()->get(Incoviba\Middleware\Authentication::class)); diff --git a/app/setup/middlewares/98_logs.php b/app/setup/middlewares/98_logs.php new file mode 100644 index 0000000..b81e521 --- /dev/null +++ b/app/setup/middlewares/98_logs.php @@ -0,0 +1,2 @@ +getContainer()->get(Psr\Log\LoggerInterface::class)); diff --git a/app/setup/middlewares/99_routes.php b/app/setup/middlewares/99_routes.php new file mode 100644 index 0000000..a08c17c --- /dev/null +++ b/app/setup/middlewares/99_routes.php @@ -0,0 +1,12 @@ +getContainer()->get('folders')->get('routes'); + $files = new FilesystemIterator($folder); + foreach ($files as $file) { + if ($file->isDir()) { + continue; + } + include_once $file->getRealPath(); + } +} +loadRoutes($app); diff --git a/app/setup/settings/env.php b/app/setup/settings/env.php new file mode 100644 index 0000000..580b775 --- /dev/null +++ b/app/setup/settings/env.php @@ -0,0 +1,2 @@ + function() { + return new DI\Container([ + 'base' => dirname(__FILE__, 3), + 'resources' => DI\String('{base}/resources'), + 'routes' => DI\String('{resources}/routes'), + 'cache' => DI\String('{base}/cache'), + 'templates' => DI\String('{resources}/views') + ]); + } +]; diff --git a/app/setup/settings/urls.php b/app/setup/settings/urls.php new file mode 100644 index 0000000..d07f846 --- /dev/null +++ b/app/setup/settings/urls.php @@ -0,0 +1,21 @@ + function() { + $urls = [ + 'base' => $_ENV['APP_URL'] ?? '', + ]; + $urls['api'] = implode('/', [ + $urls['base'], + 'api' + ]); + $urls['assets'] = implode('/', [ + $urls['base'], + 'assets' + ]); + $urls['images'] = implode('/', [ + $urls['assets'], + 'images' + ]); + return (object) $urls; + } +]; diff --git a/app/setup/setups/database.php b/app/setup/setups/database.php new file mode 100644 index 0000000..3cfd071 --- /dev/null +++ b/app/setup/setups/database.php @@ -0,0 +1,18 @@ + function(ContainerInterface $container) { + return new Incoviba\Common\Implement\Database\MySQL( + $container->has('MYSQL_HOST') ? $container->get('MYSQL_HOST') : 'db', + $container->get('MYSQL_DATABASE'), + $container->get('MYSQL_USER'), + $container->get('MYSQL_PASSWORD') + ); + }, + Incoviba\Common\Define\Connection::class => function(ContainerInterface $container) { + return new Incoviba\Common\Implement\Connection( + $container->get(Incoviba\Common\Define\Database::class) + ); + } +]; diff --git a/app/setup/setups/logs.php b/app/setup/setups/logs.php new file mode 100644 index 0000000..0ccd933 --- /dev/null +++ b/app/setup/setups/logs.php @@ -0,0 +1,32 @@ + function(ContainerInterface $container) { + return new Monolog\Logger('incoviba', [ + new Monolog\Handler\FilterHandler( + (new Monolog\Handler\RotatingFileHandler('/logs/debug.log')) + ->setFormatter(new Monolog\Formatter\LineFormatter(null, null, false, false, true)), + Monolog\Level::Debug, + Monolog\Level::Notice + ), + new Monolog\Handler\FilterHandler( + (new Monolog\Handler\RotatingFileHandler('/logs/error.log')) + ->setFormatter(new Monolog\Formatter\LineFormatter(null, null, false, false, true)), + Monolog\Level::Warning, + Monolog\Level::Error + ), + new Monolog\Handler\FilterHandler( + (new Monolog\Handler\RotatingFileHandler('/logs/critical.log')) + ->setFormatter(new Monolog\Formatter\LineFormatter(null, null, false, false, true)), + Monolog\Level::Critical + ) + ], [ + $container->get(Monolog\Processor\PsrLogMessageProcessor::class), + $container->get(Monolog\Processor\WebProcessor::class), + $container->get(Monolog\Processor\IntrospectionProcessor::class), + $container->get(Monolog\Processor\MemoryUsageProcessor::class), + $container->get(Monolog\Processor\MemoryPeakUsageProcessor::class) + ]); + } +]; diff --git a/app/setup/setups/middlewares.php b/app/setup/setups/middlewares.php new file mode 100644 index 0000000..5c5f23f --- /dev/null +++ b/app/setup/setups/middlewares.php @@ -0,0 +1,15 @@ + function(ContainerInterface $container) { + return $container->get(Nyholm\Psr7\Factory\Psr17Factory::class); + }, + Incoviba\Middleware\Authentication::class => function(ContainerInterface $container) { + return new Incoviba\Middleware\Authentication( + $container->get(Psr\Http\Message\ResponseFactoryInterface::class), + $container->get(Incoviba\Service\Login::class), + implode('/', [$container->get('APP_URL'), 'login']) + ); + } +]; diff --git a/app/setup/setups/services.php b/app/setup/setups/services.php new file mode 100644 index 0000000..3f4906f --- /dev/null +++ b/app/setup/setups/services.php @@ -0,0 +1,14 @@ + function(ContainerInterface $container) { + return new Incoviba\Service\Login( + $container->get(Incoviba\Repository\Login::class), + $container->get('COOKIE_NAME'), + $container->get('MAX_LOGIN_HOURS'), + $container->has('COOKIE_DOMAIN') ? $container->get('COOKIE_DOMAIN') : '', + $container->has('COOKIE_PATH') ? $container->get('COOKIE_PATH') : '' + ); + } +]; diff --git a/app/setup/setups/views.php b/app/setup/setups/views.php new file mode 100644 index 0000000..41cf638 --- /dev/null +++ b/app/setup/setups/views.php @@ -0,0 +1,23 @@ + function(ContainerInterface $container) { + $folders = $container->get('folders'); + $global_variables = [ + 'urls' => $container->get('urls'), + 'money_url' => '', + 'login' => $container->get(Incoviba\Service\Login::class), + 'format' => $container->get(Incoviba\Service\Format::class), + ]; + if ($global_variables['login']->isIn()) { + $global_variables['user'] = $global_variables['login']->getUser(); + } + return new Incoviba\Common\Alias\View( + $folders->get('templates'), + $folders->get('cache'), + null, + $global_variables + ); + } +]; diff --git a/app/src/Controller/Base.php b/app/src/Controller/Base.php new file mode 100644 index 0000000..2cd225d --- /dev/null +++ b/app/src/Controller/Base.php @@ -0,0 +1,90 @@ +isIn()) { + return $this->home($response, $view, $cuotaRepository, $cierreRepository); + } + return $this->login($response, $view); + } + + protected function home(ResponseInterface $response, View $view, Repository\Venta\Cuota $cuotaRepository, Repository\Venta\Cierre $cierreRepository): ResponseInterface + { + $cuotas_hoy = count($cuotaRepository->fetchHoy()) ?? 0; + $cuotas_pendientes = count($cuotaRepository->fetchPendientes()) ?? 0; + $cuotas_por_vencer = $this->getCuotasPorVencer($cuotaRepository); + $cierres_vigentes = $this->getCierresVigentes($cierreRepository); + return $view->render($response, 'home', compact('cuotas_hoy', 'cuotas_pendientes', 'cuotas_por_vencer', 'cierres_vigentes')); + } + protected function login(ResponseInterface $response, View $view): ResponseInterface + { + return $view->render($response, 'guest'); + } + protected function getCuotasPorVencer(Repository\Venta\Cuota $cuotaRepository): array + { + $cuotas = $cuotaRepository->fetchDatosPorVencer(); + $output = []; + foreach ($cuotas as $row) { + $fecha = $row['Fecha']; + $date = new DateTimeImmutable($fecha); + if (($weekday = $date->format('N')) > 5) { + $day_diff = 7 - $weekday + 1; + $date = $date->add(new DateInterval("P{$day_diff}D")); + $fecha = $date->format('Y-m-d'); + } + if (!isset($output[$fecha])) { + $output[$fecha] = []; + } + if (!isset($output[$fecha][$row['Proyecto']])) { + $output[$fecha][$row['Proyecto']] = 0; + } + $output[$fecha][$row['Proyecto']] += $row['Cantidad']; + } + foreach ($output as $fecha => $day) { + uksort($day, function($a, $b) { + return strcmp($a, $b); + }); + $output[$fecha] = $day; + } + return $output; + } + protected function getCierresVigentes(Repository\Venta\Cierre $cierreRepository): array + { + $cierres = $cierreRepository->fetchDatosVigentes(); + $output = []; + $estados = [ + 'revisado' => 'pendientes', + 'rechazado' => 'rechazados', + 'aprobado' => 'pendientes', + 'vendido' => 'promesados', + 'abandonado' => 'rechazados', + 'promesado' => 'promesados', + 'resciliado' => 'rechazados' + ]; + foreach ($cierres as $row) { + if (!isset($output[$row['Proyecto']])) { + $output[$row['Proyecto']] = [ + 'promesados' => 0, + 'pendientes' => 0, + 'rechazados' => 0, + 'total' => 0 + ]; + } + $estado = $estados[$row['Estado']]; + $output[$row['Proyecto']][$estado] += $row['Cantidad']; + $output[$row['Proyecto']]['total'] += $row['Cantidad']; + } + return $output; + } +} diff --git a/app/src/Controller/Login.php b/app/src/Controller/Login.php new file mode 100644 index 0000000..70467f5 --- /dev/null +++ b/app/src/Controller/Login.php @@ -0,0 +1,55 @@ +hasHeader('Referer') ? $request->getHeaderLine('Referer') : $view->get('urls')->base; + if ($service->isIn()) { + $redirect_uri = str_replace('/login', '', $redirect_uri); + return $response->withStatus(301)->withHeader('Location', $redirect_uri); + } + if ($request->hasHeader('X-Redirect-URI')) { + $redirect_uri = $request->getHeaderLine('X-Redirect-URI'); + } + return $view->render($response, 'login.form', compact('redirect_uri')); + } + public function login(ServerRequestInterface $request, ResponseInterface $response, Repository\User $userRepository, Service\Login $service): ResponseInterface + { + $body = $request->getParsedBody(); + $user = $userRepository->fetchByName($body['name']); + $output = [ + 'name' => $user->name, + 'login' => false + ]; + if ($user->validate($body['password'])) { + $output['login'] = $service->login($user); + } + $response->getBody()->write(json_encode($output)); + return $response->withHeader('Content-Type', 'application/json'); + } + public function logout(ServerRequestInterface $request, ResponseInterface $response, Repository\Login $loginRepository, Service\Login $service): ResponseInterface + { + $output = [ + 'name' => '', + 'logout' => false + ]; + try { + $user = $service->getUser(); + $output = [ + 'name' => $user->name, + 'logout' => $service->logout($user) + ]; + } catch (PDOException) {} + $response->getBody()->write(json_encode($output)); + return $response->withHeader('Content-Type', 'application/json'); + } +} diff --git a/app/src/Controller/Proyectos.php b/app/src/Controller/Proyectos.php new file mode 100644 index 0000000..9ef8c47 --- /dev/null +++ b/app/src/Controller/Proyectos.php @@ -0,0 +1,21 @@ +render($response, 'proyectos.list'); + } + public function list(ServerRequestInterface $request, ResponseInterface $response, Repository\Proyecto $proyectoRepository): ResponseInterface + { + $proyectos = $proyectoRepository->fetchAllActive(); + $response->getBody()->write(json_encode(['proyectos' => $proyectos, 'total' => count($proyectos)])); + return $response->withHeader('Content-Type', 'application/json'); + } +} diff --git a/app/src/Controller/Users.php b/app/src/Controller/Users.php new file mode 100644 index 0000000..cfa82ff --- /dev/null +++ b/app/src/Controller/Users.php @@ -0,0 +1,11 @@ +fetchPendientes(); + $cuotas_pendientes = []; + $today = new DateTimeImmutable(); + $formatter = new IntlDateFormatter('es_ES'); + $formatter->setPattern('EEEE dd'); + foreach ($cuotas as $cuota) { + $date = new DateTimeImmutable($cuota['fecha']); + $day = clone $date; + $weekday = $date->format('N'); + if ($weekday > 5) { + $diff = 7 - $weekday + 1; + $day = $day->add(new DateInterval("P{$diff}D")); + } + $cuotas_pendientes []= [ + 'id' => $cuota['cuota_id'], + 'venta_id' => $cuota['venta_id'], + 'Proyecto' => $cuota['Proyecto'], + 'Departamento' => $cuota['Departamento'], + 'Valor' => $cuota['Valor'], + 'Dia' => $formatter->format($day), + 'Numero' => $cuota['Numero'], + 'Propietario' => $cuota['Propietario'], + 'Banco' => $cuota['Banco'], + 'Fecha Cheque' => $date->format('d-m-Y'), + 'Vencida' => $today->diff($date)->days, + 'Fecha ISO' => $date->format('Y-m-d') + ]; + } + return $view->render($response, 'ventas.cuotas.pendientes', compact('cuotas_pendientes')); + } + public function depositar(ServerRequestInterface $request, ResponseInterface $response, Repository\Venta\Cuota $cuotaRepository, Service\Ventas\Pago $pagoService): ResponseInterface + { + $body = $request->getBody(); + $json = json_decode($body->getContents()); + $cuota_id = $json->cuota_id; + $cuota = $cuotaRepository->fetchById($cuota_id); + $output = [ + 'cuota_id' => $cuota_id, + 'depositada' => $pagoService->depositar($cuota->pago) + ]; + $response->getBody()->write(json_encode($output)); + return $response->withHeader('Content-Type', 'application/json'); + } +} diff --git a/app/src/Controller/Ventas/Precios.php b/app/src/Controller/Ventas/Precios.php new file mode 100644 index 0000000..c4ef615 --- /dev/null +++ b/app/src/Controller/Ventas/Precios.php @@ -0,0 +1,24 @@ +render($response, 'ventas.precios.list'); + } + public function proyecto(ServerRequestInterface $request, ResponseInterface $response, Service\Ventas\Precio $precioService): ResponseInterface + { + $body = $request->getBody(); + $json = json_decode($body->getContents()); + $proyecto_id = $json->proyecto_id; + $precios = $precioService->getByProyecto($proyecto_id); + $response->getBody()->write(json_encode(['precios' => $precios, 'total' => count($precios)])); + return $response->withHeader('Content-Type', 'application/json'); + } +} diff --git a/app/src/Middleware/Authentication.php b/app/src/Middleware/Authentication.php new file mode 100644 index 0000000..32d3e9f --- /dev/null +++ b/app/src/Middleware/Authentication.php @@ -0,0 +1,48 @@ +service->isIn() or $this->isValid($request)) { + return $handler->handle($request); + } + $response = $this->responseFactory->createResponse(301, 'Not logged in'); + return $response->withHeader('Location', $this->login_url) + ->withHeader('X-Redirected-URI', (string) $request->getUri()); + } + + protected function isValid(ServerRequestInterface $request): bool + { + $uri = $request->getUri(); + $current_path = $uri->getPath(); + $current_url = implode('', [ + "{$uri->getScheme()}://", + $uri->getHost() . ($uri->getPort() !== null ? ":{$uri->getPort()}" : ''), + $uri->getPath() + ]); + + $valid_paths = [ + '/', + ]; + if (in_array($current_path, $valid_paths, true)) { + return true; + } + $valid_uris = [ + $this->login_url, + ]; + if (in_array($current_url, $valid_uris, true)) { + return true; + } + return false; + } +} diff --git a/app/src/Model/Banco.php b/app/src/Model/Banco.php new file mode 100644 index 0000000..1852ff2 --- /dev/null +++ b/app/src/Model/Banco.php @@ -0,0 +1,16 @@ + $this->nombre ?? '' + ]); + } +} diff --git a/app/src/Model/Comuna.php b/app/src/Model/Comuna.php new file mode 100644 index 0000000..3bf746d --- /dev/null +++ b/app/src/Model/Comuna.php @@ -0,0 +1,18 @@ + $this->descripcion, + 'provincia' => $this->provincia + ]); + } +} diff --git a/app/src/Model/Direccion.php b/app/src/Model/Direccion.php new file mode 100644 index 0000000..7795ad5 --- /dev/null +++ b/app/src/Model/Direccion.php @@ -0,0 +1,22 @@ + $this->calle, + 'numero' => $this->numero, + 'extra' => $this->extra, + 'comuna' => $this->comuna + ]); + } +} diff --git a/app/src/Model/Inmobiliaria.php b/app/src/Model/Inmobiliaria.php new file mode 100644 index 0000000..cc7778c --- /dev/null +++ b/app/src/Model/Inmobiliaria.php @@ -0,0 +1,38 @@ +rut, 0, ',', '.'), + $this->dv + ]); + } + + public function jsonSerialize(): mixed + { + return [ + 'rut' => $this->rut, + 'dv' => $this->dv ?? '', + 'rut_formateado' => $this->rut(), + 'razon' => $this->razon ?? '', + 'abreviacion' => $this->abreviacion ?? '', + 'cuenta' => $this->cuenta ?? '', + 'banco' => $this->banco ?? '', + 'tipo_sociedad' => $this->tipoSociedad ?? '' + ]; + } +} diff --git a/app/src/Model/Inmobiliaria/TipoSociedad.php b/app/src/Model/Inmobiliaria/TipoSociedad.php new file mode 100644 index 0000000..dc71047 --- /dev/null +++ b/app/src/Model/Inmobiliaria/TipoSociedad.php @@ -0,0 +1,16 @@ + $this->abreviacion + ]); + } +} diff --git a/app/src/Model/Login.php b/app/src/Model/Login.php new file mode 100644 index 0000000..fb66590 --- /dev/null +++ b/app/src/Model/Login.php @@ -0,0 +1,25 @@ + $this->user->id, + 'selector' => $this->selector, + 'token' => $this->token, + 'date_time' => $this->dateTime->format('Y-m-d H:i:s'), + 'status' => $this->status + ]); + } +} diff --git a/app/src/Model/Provincia.php b/app/src/Model/Provincia.php new file mode 100644 index 0000000..1f2f387 --- /dev/null +++ b/app/src/Model/Provincia.php @@ -0,0 +1,18 @@ + $this->descripcion, + 'region' => $this->region + ]); + } +} diff --git a/app/src/Model/Proyecto.php b/app/src/Model/Proyecto.php new file mode 100644 index 0000000..f9f21d2 --- /dev/null +++ b/app/src/Model/Proyecto.php @@ -0,0 +1,32 @@ + $this->inmobiliaria, + 'descripcion' => $this->descripcion, + 'direccion' => $this->direccion, + 'terreno' => $this->terreno, + 'superficie' => $this->superficie, + 'corredor' => $this->corredor, + 'pisos' => $this->pisos, + 'subterraneos' => $this->subterraneos + ]); + } +} diff --git a/app/src/Model/Proyecto/ProyectoTipoUnidad.php b/app/src/Model/Proyecto/ProyectoTipoUnidad.php new file mode 100644 index 0000000..a755bb7 --- /dev/null +++ b/app/src/Model/Proyecto/ProyectoTipoUnidad.php @@ -0,0 +1,42 @@ +util, $this->logia, $this->terraza], function($sum, $item) {return $sum + $item;}, 0); + } + public function vendible(): float + { + return array_reduce([$this->util, $this->logia, $this->terraza / 2], function($sum, $item) {return $sum + $item;}, 0); + } + + public function jsonSerialize(): mixed + { + return array_merge(parent::jsonSerialize(), [ + 'proyecto' => $this->proyecto, + 'tipo_unidad' => $this->tipoUnidad, + 'nombre' => $this->nombre, + 'abreviacion' => $this->abreviacion, + 'util' => $this->util, + 'logia' => $this->logia, + 'terraza' => $this->terraza, + 'superficie' => $this->superficie(), + 'vendible' => $this->vendible(), + 'descripcion' => $this->descripcion + ]); + } +} diff --git a/app/src/Model/Proyecto/Superficie.php b/app/src/Model/Proyecto/Superficie.php new file mode 100644 index 0000000..72d6e5f --- /dev/null +++ b/app/src/Model/Proyecto/Superficie.php @@ -0,0 +1,8 @@ + $this->descripcion, + 'numeral' => $this->numeral, + 'numeracion' => $this->numeracion ?? 0 + ]); + } +} diff --git a/app/src/Model/Role.php b/app/src/Model/Role.php new file mode 100644 index 0000000..e27c6a9 --- /dev/null +++ b/app/src/Model/Role.php @@ -0,0 +1,7 @@ + $this->descripcion + ]); + } +} diff --git a/app/src/Model/User.php b/app/src/Model/User.php new file mode 100644 index 0000000..2647b88 --- /dev/null +++ b/app/src/Model/User.php @@ -0,0 +1,28 @@ +password); + } + public function isAdmin(): bool + { + return false; + } + + public function jsonSerialize(): mixed + { + return array_merge(parent::jsonSerialize(), [ + 'name' => $this->name + ]); + } +} diff --git a/app/src/Model/Venta/Cierre.php b/app/src/Model/Venta/Cierre.php new file mode 100644 index 0000000..25d3009 --- /dev/null +++ b/app/src/Model/Venta/Cierre.php @@ -0,0 +1,26 @@ + $this->proyecto->id, + 'precio' => $this->precio, + 'date_time' => $this->dateTime->format('Y-m-d H:i:s'), + 'relacionado' => $this->relacionado, + 'propietario' => $this->propietario->rut + ]); + } +} diff --git a/app/src/Model/Venta/Cuota.php b/app/src/Model/Venta/Cuota.php new file mode 100644 index 0000000..188f4c0 --- /dev/null +++ b/app/src/Model/Venta/Cuota.php @@ -0,0 +1,38 @@ + $this->pie->id, + 'fecha' => $this->fecha->format('Y-m-d H:i:s'), + 'valor' => $this->valor, + 'estado' => $this->estado ?? false, + 'banco' => $this->banco, + 'fecha_pago' => $this->fechaPago->format('Y-m-d H:i:s') ?? '', + 'abonado' => $this->abonado ?? false, + 'fecha_abonado' => $this->fechaAbonado->format('Y-m-d H:i:s') ?? '', + 'uf' => $this->uf ?? 1, + 'pago' => $this->pago ?? '', + 'numero' => $this->numero ?? '' + ]); + } +} diff --git a/app/src/Model/Venta/Datos.php b/app/src/Model/Venta/Datos.php new file mode 100644 index 0000000..b9a7ebd --- /dev/null +++ b/app/src/Model/Venta/Datos.php @@ -0,0 +1,27 @@ + $this->sexo ?? '', + 'estado_civil' => $this->estado_civil ?? '', + 'profesion' => $this->profesion ?? '', + 'direccion' => $this->direccion ?? '', + 'telefono' => $this->telefono ?? '', + 'email' => $this->email ?? '' + ]; + } +} diff --git a/app/src/Model/Venta/EstadoPago.php b/app/src/Model/Venta/EstadoPago.php new file mode 100644 index 0000000..e94f8d8 --- /dev/null +++ b/app/src/Model/Venta/EstadoPago.php @@ -0,0 +1,22 @@ + $this->pago->id, + 'fecha' => $this->fecha->format('Y-m-d'), + 'tipo_estado_pago_id' => $this->tipoEstadoPago->id + ]); + } + +} diff --git a/app/src/Model/Venta/EstadoPrecio.php b/app/src/Model/Venta/EstadoPrecio.php new file mode 100644 index 0000000..815793f --- /dev/null +++ b/app/src/Model/Venta/EstadoPrecio.php @@ -0,0 +1,21 @@ + $this->precio->id, + 'tipo_estado_precio' => $this->tipoEstadoPrecio, + 'fecha' => $this->fecha->format('Y-m-d') + ]); + } +} diff --git a/app/src/Model/Venta/Pago.php b/app/src/Model/Venta/Pago.php new file mode 100644 index 0000000..08f5da9 --- /dev/null +++ b/app/src/Model/Venta/Pago.php @@ -0,0 +1,32 @@ + $this->valor, + 'banco' => $this->banco ?? '', + 'tipo_pago' => $this->tipoPago ?? '', + 'identificador' => $this->identificador ?? '', + 'fecha' => $this->fecha->format('Y-m-d H:i:S') ?? '', + 'uf' => $this->uf ?? 1, + 'pagador' => $this->pagador ?? '', + 'asociado' => $this->asociado ?? '' + ]); + } +} diff --git a/app/src/Model/Venta/Pie.php b/app/src/Model/Venta/Pie.php new file mode 100644 index 0000000..3a1f4ad --- /dev/null +++ b/app/src/Model/Venta/Pie.php @@ -0,0 +1,27 @@ + $this->fecha->format('Y-m-d H:i:s'), + 'valor' => $this->valor, + 'uf' => $this->uf ?? 1, + 'cuotas' => $this->cuotas, + 'asociado' => $this->asociado ?? '', + 'reajuste' => $this->reajuste ?? '' + ]); + } +} diff --git a/app/src/Model/Venta/Precio.php b/app/src/Model/Venta/Precio.php new file mode 100644 index 0000000..0b2094e --- /dev/null +++ b/app/src/Model/Venta/Precio.php @@ -0,0 +1,23 @@ + $this->unidad, + 'valor' => $this->valor, + 'estado_precio' => $this->current ?? [], + 'estados' => $this->estados ?? null + ]); + } +} diff --git a/app/src/Model/Venta/Propietario.php b/app/src/Model/Venta/Propietario.php new file mode 100644 index 0000000..77300eb --- /dev/null +++ b/app/src/Model/Venta/Propietario.php @@ -0,0 +1,46 @@ +rut, 0, ',', '.'), + $this->dv + ]); + } + public function nombreCompleto(): string + { + return implode(' ', [ + $this->nombres, + implode(' ', $this->apellidos) + ]); + } + + public function jsonSerialize(): mixed + { + return array_merge([ + 'rut' => $this->rut, + 'dv' => $this->dv, + 'rut_formateado' => $this->rut(), + 'nombres' => $this->nombres, + 'apellidos' => $this->apellidos, + 'nombre_completo' => $this->nombreCompleto(), + ], $this->datos->jsonSerialize(), [ + 'representante' => $this->representante ?? '', + 'otro' => $this->otro ?? '' + ]); + } +} diff --git a/app/src/Model/Venta/TipoEstadoPago.php b/app/src/Model/Venta/TipoEstadoPago.php new file mode 100644 index 0000000..2d00621 --- /dev/null +++ b/app/src/Model/Venta/TipoEstadoPago.php @@ -0,0 +1,8 @@ + $this->orden + ]); + } +} diff --git a/app/src/Model/Venta/Unidad.php b/app/src/Model/Venta/Unidad.php new file mode 100644 index 0000000..3040504 --- /dev/null +++ b/app/src/Model/Venta/Unidad.php @@ -0,0 +1,25 @@ + $this->subtipo, + 'piso' => $this->piso, + 'descripcion' => $this->descripcion, + 'orientacion' => $this->orientacion, + 'proyecto_tipo_unidad' => $this->proyectoTipoUnidad + ]); + } +} diff --git a/app/src/Repository/Banco.php b/app/src/Repository/Banco.php new file mode 100644 index 0000000..7a35492 --- /dev/null +++ b/app/src/Repository/Banco.php @@ -0,0 +1,35 @@ +setTable('banco'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'nombre' => [] + ]; + return $this->parseData(new Model\Banco(), $data, $map); + } + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['nombre'], + [$model->nombre] + ); + return $model; + } + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['nombre'], $new_data); + } +} diff --git a/app/src/Repository/Comuna.php b/app/src/Repository/Comuna.php new file mode 100644 index 0000000..ddb54e1 --- /dev/null +++ b/app/src/Repository/Comuna.php @@ -0,0 +1,51 @@ +setTable('comuna'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'descripcion' => [], + 'provincia' => [ + 'function' => function($data) { + return $this->provinciaRepository->fetchById($data['provincia']); + } + ] + ]; + return $this->parseData(new Model\Comuna(), $data, $map); + } + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['descripcion', 'provincia'], + [$model->descripcion, $model->provincia->id] + ); + return $model; + } + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['descripcion', 'provincia'], $new_data); + } + + public function fetchByDescripcion(string $descripcion): Define\Model + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `descripcion` = ?"; + return $this->fetchOne($query, [$descripcion]); + } + public function fetchByProvincia(int $provincia_id): array + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `provincia` = ?"; + return $this->fetchMany($query, [$provincia_id]); + } +} diff --git a/app/src/Repository/Direccion.php b/app/src/Repository/Direccion.php new file mode 100644 index 0000000..87bd955 --- /dev/null +++ b/app/src/Repository/Direccion.php @@ -0,0 +1,48 @@ +setTable('direccion'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'calle' => [], + 'numero' => [], + 'extra' => [], + 'comuna' => [ + 'function' => function($data) { + return $this->comunaRepository->fetchById($data['comuna']); + } + ] + ]; + return $this->parseData(new Model\Direccion(), $data, $map); + } + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['calle', 'numero', 'extra', 'comuna'], + [$model->calle, $model->numero, $model->extra, $model->comuna->id] + ); + return $model; + } + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['calle', 'numero', 'extra', 'comuna'], $new_data); + } + + public function fetchByCalleAndNumero(string $calle, int $numero): array + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `calle` = ? AND `numero` = ?"; + return $this->fetchMany($query, [$calle, $numero]); + } +} diff --git a/app/src/Repository/Inmobiliaria.php b/app/src/Repository/Inmobiliaria.php new file mode 100644 index 0000000..7ae90c6 --- /dev/null +++ b/app/src/Repository/Inmobiliaria.php @@ -0,0 +1,55 @@ +setTable('inmobiliaria'); + } + + protected function getKey(): string + { + return 'rut'; + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'dv' => [], + 'razon' => [], + 'abreviacion' => [], + 'cuenta' => [], + 'banco' => [ + 'function' => function($data) { + return $this->bancoRepository->fetchById($data['banco']); + } + ], + 'sociedad' => [ + 'property' => 'tipoSociedad', + 'function' => function($data) { + return $this->tipoSociedadRepository->fetchById($data['sociedad']); + } + ] + ]; + return $this->parseData(new Model\Inmobiliaria(), $data, $map); + } + public function save(Define\Model $model): Define\Model + { + $model->rut = $this->saveNew( + ['dv', 'razon', 'abreviacion', 'cuenta', 'banco', 'sociedad'], + [$model->dv, $model->razon, $model->abreviacion, $model->cuenta, $model->banco->id, $model->tipoSociedad->id] + ); + return $model; + } + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['dv', 'razon', 'abreviacion', 'cuenta', 'banco', 'sociedad'], $new_data); + } +} diff --git a/app/src/Repository/Inmobiliaria/TipoSociedad.php b/app/src/Repository/Inmobiliaria/TipoSociedad.php new file mode 100644 index 0000000..0d2a05f --- /dev/null +++ b/app/src/Repository/Inmobiliaria/TipoSociedad.php @@ -0,0 +1,36 @@ +setTable('tipo_sociedad'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'descripcion' => [], + 'abreviacion' => [] + ]; + return $this->parseData(new Model\Inmobiliaria\TipoSociedad(), $data, $map); + } + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['descripcion', 'abreviacion'], + [$model->descripcion, $model->abreviacion] + ); + return $model; + } + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['descripcion', 'abreviacion'], $new_data); + } +} diff --git a/app/src/Repository/Login.php b/app/src/Repository/Login.php new file mode 100644 index 0000000..0cfa3e4 --- /dev/null +++ b/app/src/Repository/Login.php @@ -0,0 +1,77 @@ +setTable('logins'); + } + + + public function create(?array $data = null): Define\Model + { + $map = [ + 'user_id' => [ + 'property' => 'user', + 'function' => function($data) { + return $this->userRepository->fetchById($data['user_id']); + } + ], + 'selector' => [], + 'token' => [], + 'time' => [ + 'property' => 'dateTime', + 'function' => function($data) { + return new DateTimeImmutable($data['time']); + } + ], + 'status' => [ + 'function' => function($data) { + return $data['status'] != 0; + } + ] + ]; + return $this->parseData(new Model\Login(), $data, $map); + } + + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['user_id', 'selector', 'token', 'time', 'status'], + [$model->user->id, $model->selector, $model->token, $model->dateTime->format('Y-m-d H:i:s'), $model->status ? 1 : 0]); + return $model; + } + + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['user_id', 'selector', 'token', 'time', 'status'], $new_data); + } + + public function fetchByUser(int $user_id): array + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `user_id` = ?"; + return $this->fetchMany($query, [$user_id]); + } + public function fetchActiveByUser(int $user_id): Model\Login + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `user_id` = ? AND `status` = 1"; + return $this->fetchOne($query, [$user_id]); + } + public function fetchBySelectorAndToken(string $selector, string $token): Model\Login + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `selector` = ? AND `token` = ?"; + return $this->fetchOne($query, [$selector, $token]); + } + public function fetchActiveBySelector(string $selector): Model\Login + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `selector` = ? AND `status` = 1"; + return $this->fetchOne($query, [$selector]); + } +} diff --git a/app/src/Repository/Provincia.php b/app/src/Repository/Provincia.php new file mode 100644 index 0000000..3e8406e --- /dev/null +++ b/app/src/Repository/Provincia.php @@ -0,0 +1,51 @@ +setTable('provincia'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'descripcion' => [], + 'region' => [ + 'function' => function($data) { + return $this->regionRepository->fetchById($data['region']); + } + ] + ]; + return $this->parseData(new Model\Provincia(), $data, $map); + } + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['descripcion', 'region'], + [$model->descripcion, $model->region->id] + ); + return $model; + } + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['descripcion', 'region'], $new_data); + } + + public function fetchByDescripcion(string $description): Define\Model + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `descripcion` = ?"; + return $this->fetchOne($query, [$description]); + } + public function fetchByRegion(int $region_id): array + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `region` = ?"; + return $this->fetchMany($query, [$region_id]); + } +} diff --git a/app/src/Repository/Proyecto.php b/app/src/Repository/Proyecto.php new file mode 100644 index 0000000..0c8d4e8 --- /dev/null +++ b/app/src/Repository/Proyecto.php @@ -0,0 +1,88 @@ +setTable('proyecto'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'inmobiliaria' => [ + 'function' => function($data) { + return $this->inmobiliariaRepository->fetchById($data['inmobiliaria']); + } + ], + 'descripcion' => [], + 'direccion' => [ + 'function' => function($data) { + return $this->direccionRepository->fetchById($data['direccion']); + } + ], + 'superficie_terreno' => [ + 'property' => 'terreno', + 'function' => function($data) { + $terreno = new Model\Proyecto\Terreno(); + $terreno->superficie = $data['superficie_terreno']; + $terreno->valor = $data['valor_terreno']; + return $terreno; + } + ], + 'superficie_sobre_nivel' => [ + 'property' => 'superficie', + 'function' => function($data) { + $superficie = new Model\Proyecto\Superficie(); + $superficie->sobre_nivel = $data['superficie_sobre_nivel']; + $superficie->bajo_nivel = $data['superficie_bajo_nivel']; + return $superficie; + } + ], + 'corredor' => [], + 'pisos' => [], + 'subterraneos' => [] + ]; + return $this->parseData(new Model\Proyecto(), $data, $map); + } + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['inmobiliaria', 'descripcion', 'direccion', 'superficie_terreno', 'valor_terreno', 'corredor', + 'superficie_sobre_nivel', 'superficie_bajo_nivel', 'pisos', 'subterraneos'], + [$model->inmobiliaria->rut, $model->descripcion, $model->direccion->id, $model->terreno->superficie, + $model->terreno->valor, $model->corredor, $model->superficie->sobre_nivel, + $model->superficie->bajo_nivel, $model->pisos, $model->subterraneos] + ); + return $model; + } + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['inmobiliaria', 'descripcion', 'direccion', 'superficie_terreno', + 'valor_terreno', 'corredor', 'superficie_sobre_nivel', 'superficie_bajo_nivel', 'pisos', + 'subterraneos'], $new_data); + } + public function fetchByName(string $name): Define\Model + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `name` = ?"; + return $this->fetchOne($query, [$name]); + } + public function fetchAllActive(): array + { + $query = "SELECT a.* +FROM `{$this->getTable()}` a + JOIN (SELECT e1.* FROM `estado_proyecto` e1 JOIN (SELECT MAX(`id`) AS 'id', `proyecto` FROM `estado_proyecto` GROUP BY `proyecto`) e0 ON e0.`id` = e1.`id`) ep ON ep.`proyecto` = a.`id` + JOIN `tipo_estado_proyecto` tep ON tep.`id` = ep.`estado` + JOIN `etapa_proyecto` et ON et.`id` = tep.`etapa` +WHERE et.`orden` BETWEEN 4 AND 8 +ORDER BY a.`descripcion`"; + return $this->fetchMany($query); + } +} diff --git a/app/src/Repository/Proyecto/ProyectoTipoUnidad.php b/app/src/Repository/Proyecto/ProyectoTipoUnidad.php new file mode 100644 index 0000000..1500f26 --- /dev/null +++ b/app/src/Repository/Proyecto/ProyectoTipoUnidad.php @@ -0,0 +1,54 @@ +setTable('proyecto_tipo_unidad'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'proyecto' => [ + 'function' => function($data) { + return $this->proyectoRepository->fetchById($data['proyecto']); + } + ], + 'tipo' => [ + 'property' => 'tipoUnidad', + 'function' => function($data) { + return $this->tipoUnidadRepository->fetchById($data['tipo']); + } + ], + 'nombre' => [], + 'abreviacion' => [], + 'm2' => [ + 'property' => 'util' + ], + 'logia' => [], + 'terraza' => [], + 'descripcion' => [] + ]; + return $this->parseData(new Model\Proyecto\ProyectoTipoUnidad(), $data, $map); + } + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['proyecto', 'tipo', 'nombre', 'abreviacion', 'm2', 'logia', 'terraza', 'descripcion'], + [$model->proyecto->id, $model->tipoUnidad->id, $model->nombre, $model->abreviacion, $model->util, $model->logia, $model->terraza, $model->descripcion] + ); + return $model; + } + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['proyecto', 'tipo', 'nombre', 'abreviacion', 'util', 'logia', 'terraza', 'descripcion'], $new_data); + } +} diff --git a/app/src/Repository/Region.php b/app/src/Repository/Region.php new file mode 100644 index 0000000..34287e6 --- /dev/null +++ b/app/src/Repository/Region.php @@ -0,0 +1,53 @@ +setTable('region'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'descripcion' => [], + 'numeral' => [], + 'numeracion' => [] + ]; + return $this->parseData(new Model\Region(), $data, $map); + } + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['descripcion', 'numeral', 'numeracion'], + [$model->descripcion, $model->numeral, $model->numeracion] + ); + return $model; + } + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['descripcion', 'numeral', 'numeracion'], $new_data); + } + + public function fetchByDescripcion(string $descripcion): Define\Model + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `descripcion` = ?"; + return $this->fetchOne($query, [$descripcion]); + } + public function fetchByNumeral(string $numeral): Define\Model + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `numeral` = ?"; + return $this->fetchOne($query, [$numeral]); + } + public function fetchByNumeracion(int $numeracion): Define\Model + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `numeracion` = ?"; + return $this->fetchOne($query, [$numeracion]); + } +} diff --git a/app/src/Repository/User.php b/app/src/Repository/User.php new file mode 100644 index 0000000..97ae151 --- /dev/null +++ b/app/src/Repository/User.php @@ -0,0 +1,46 @@ +setTable('users'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'name' => [], + 'password' => [], + 'enabled' => [ + 'function' => function($data) { + return $data['enabled'] != 0; + } + ] + ]; + return $this->parseData(new Model\User(), $data, $map); + } + + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew(['name', 'password', 'enabled'], [$model->name, $model->password, $model->enabled ? 1 : 0]); + return $model; + } + + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['name', 'password', 'enabled'], $new_data); + } + + public function fetchByName(string $name): Model\User + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `name` = ?"; + return $this->fetchOne($query, [$name]); + } +} diff --git a/app/src/Repository/Venta/Cierre.php b/app/src/Repository/Venta/Cierre.php new file mode 100644 index 0000000..6366347 --- /dev/null +++ b/app/src/Repository/Venta/Cierre.php @@ -0,0 +1,82 @@ +setTable('cierre'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'proyecto' => [ + 'function' => function($data) { + return $this->proyectoRepository->fetchById($data['proyecto']); + } + ], + 'precio' => [], + 'fecha' => [ + 'property' => 'dateTime', + 'function' => function($data) { + return new DateTimeImmutable($data['fecha']); + } + ], + 'relacionado' => [ + 'function' => function($data) { + return $data['relacionado'] !== 0; + } + ], + 'propietario' => [ + 'function' => function($data) { + return $this->propietarioRepository->fetchById($data['propietario']); + } + ] + ]; + return $this->parseData(new Model\Venta\Cierre(), $data, $map); + } + + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['proyecto', 'precio', 'fecha', 'relacionado', 'propietario'], + [$model->proyecto->id, $model->precio, $model->fecha->format('Y-m-d H:i:s'), $model->relacionado ? 1 : 0, $model->propietario->rut] + ); + return $model; + } + + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['proyecto', 'precio', 'fecha', 'relacionado', 'propietario'], $new_data); + } + + public function fetchDatosVigentes(): array + { + $query = " +SELECT `proyecto`.`descripcion` AS 'Proyecto', tec.`descripcion` AS 'Estado', COUNT(a.`id`) AS 'Cantidad' +FROM `{$this->getTable()}` a + JOIN (SELECT e1.* + FROM `estado_cierre` e1 + JOIN (SELECT MAX(`id`) AS id, `cierre` FROM `estado_cierre` GROUP BY `cierre`) e0 ON e0.`id` = e1.`id`) ec ON ec.`cierre` = a.`id` + JOIN `tipo_estado_cierre` tec ON tec.`id` = ec.`tipo` + JOIN `proyecto` ON `proyecto`.`id` = a.`proyecto` +GROUP BY `proyecto`.`descripcion`, tec.`descripcion`"; + $results = $this->connection->execute($query)->fetchAll(PDO::FETCH_ASSOC); + if ($results === false) { + throw new EmptyResult($query); + } + return $results; + } +} diff --git a/app/src/Repository/Venta/Cuota.php b/app/src/Repository/Venta/Cuota.php new file mode 100644 index 0000000..341d554 --- /dev/null +++ b/app/src/Repository/Venta/Cuota.php @@ -0,0 +1,161 @@ +setTable('cuota'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'pie' => [ + 'function' => function($data) { + return $this->pieRepository->fetchById($data['pie']); + } + ], + 'fecha' => [ + 'function' => function($data) { + return new DateTimeImmutable($data['fecha']); + } + ], + 'valor' => [], + 'estado' => [ + 'function' => function($data) { + return $data['estado'] !== 0; + } + ], + 'banco' => [ + 'function' => function($data) { + if ($data['banco'] === null or $data['banco'] === '') { + return null; + } + return $this->bancoRepository->fetchById($data['banco']); + } + ], + 'fecha_pago' => [ + 'property' => 'fechaPago', + 'function' => function($data) { + if ($data['fecha_pago'] === null) { + return null; + } + return new DateTimeImmutable($data['fecha_pago']); + } + ], + 'abonado' => [ + 'function' => function($data) { + if ($data['abonado'] === null) { + return null; + } + return $data['abonado'] !== 0; + } + ], + 'fecha_abonado' => [ + 'property' => 'fechaAbonado', + 'function' => function($data) { + if ($data['fecha_abonado'] === null) { + return null; + } + return new DateTimeImmutable($data['fecha_abonado']); + } + ], + 'uf' => [], + 'pago' => [ + 'function' => function($data) { + if ($data['pago'] === null) { + return null; + } + return $this->pagoRepository->fetchById($data['pago']); + } + ], + 'numero' => [] + ]; + return $this->parseData(new Model\Venta\Cuota(), $data, $map); + } + + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['pie', 'fecha', 'valor', 'estado', 'banco', 'fecha_pago', 'abonado', 'fecha_abonado', 'uf', 'pago', 'numero'], + [$model->pie->id, $model->fecha->format('Y-m-d H:i:s'), $model->valor, $model->estado ? 1 : 0, $model?->banco->id, + $model?->fechaPago->format('Y-m-d H:i:s'), $model?->abonado ? 1 : 0, $model?->fechaAbonado->format('Y-m-d H:i:s'), + $model?->uf, $model?->pago->id, $model?->numero] + ); + return $model; + } + + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['pie', 'fecha', 'valor', 'estado', 'banco', 'fecha_pago', 'abonado', 'fecha_abonado', 'uf', 'pago', 'numero'], $new_data); + } + + public function fetchHoy(): array + { + $query = "SELECT a.* +FROM `{$this->getTable()}` a + JOIN `pago` ON `pago`.`id` = a.`pago` + JOIN (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 ON ep.`pago` = `pago`.`id` + JOIN `tipo_estado_pago` tep ON tep.`id` = ep.`estado` + JOIN `venta` ON `venta`.`pie` = a.`pie` + 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` = `venta`.`id` + JOIN `tipo_estado_venta` tev ON tev.`id` = ev.`estado` +WHERE tep.`descripcion` = 'no pagado' AND `pago`.`fecha` = CURDATE() + AND tev.`descripcion` IN ('vigente', 'escriturando', 'firmado por inmobiliaria')"; + return $this->fetchMany($query); + } + public function fetchPendientes(): array + { + $query = "SELECT a.`id` AS 'cuota_id', `venta`.`id` AS 'venta_id', `proyecto`.`descripcion` AS 'Proyecto', `unidad`.`descripcion` AS 'Departamento', + `pago`.`valor` AS 'Valor', `pago`.`fecha`, CONCAT_WS(' - ', a.`numero`, `pie`.`cuotas`) AS 'Numero', `banco`.`nombre` AS 'Banco', + CONCAT_WS(' ', `propietario`.`nombres`, `propietario`.`apellido_paterno`, `propietario`.`apellido_materno`) AS 'Propietario' +FROM `{$this->getTable()}` a + JOIN `pago` ON `pago`.`id` = a.`pago` + JOIN (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 ON ep.`pago` = `pago`.`id` + JOIN `tipo_estado_pago` tep ON tep.`id` = ep.`estado` + JOIN `pie` ON `pie`.`id` = a.`pie` + JOIN `venta` ON `venta`.`pie` = a.`pie` + 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` = `venta`.`id` + JOIN `tipo_estado_venta` tev ON tev.`id` = ev.`estado` + JOIN `propietario` ON `propietario`.`rut` = `venta`.`propietario` + JOIN `propiedad_unidad` pu ON pu.`propiedad` = `venta`.`propiedad` + JOIN `unidad` ON `unidad`.`id` = pu.`unidad` AND pu.`principal` = 1 + JOIN `proyecto_tipo_unidad` ptu ON ptu.`id` = `unidad`.`pt` + JOIN `proyecto` ON `proyecto`.`id` = ptu.`proyecto` + JOIN `banco` ON `banco`.`id` = `pago`.`banco` +WHERE tep.`descripcion` = 'no pagado' AND `pago`.`fecha` < CURDATE() + AND tev.`descripcion` IN ('vigente', 'escriturando', 'firmado por inmobiliaria') +ORDER BY `pago`.`fecha` DESC"; + return $this->fetchAsArray($query); + } + public function fetchDatosPorVencer(): array + { + $query = "SELECT `pago`.`fecha` AS 'Fecha', `proyecto`.`descripcion` AS 'Proyecto', COUNT(a.`id`) AS 'Cantidad' +FROM `{$this->getTable()}` a + JOIN `pago` ON `pago`.`id` = a.`pago` + JOIN (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 ON ep.`pago` = `pago`.`id` + JOIN `tipo_estado_pago` tep ON tep.`id` = ep.`estado` + JOIN `venta` ON `venta`.`pie` = a.`pie` + 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` = `venta`.`id` + JOIN `tipo_estado_venta` tev ON tev.`id` = ev.`estado` + JOIN `propiedad_unidad` pu ON pu.`propiedad` = `venta`.`propiedad` AND pu.`principal` = 1 + JOIN `unidad` ON `unidad`.`id` = pu.`unidad` + JOIN `proyecto_tipo_unidad` ptu ON ptu.`id` = `unidad`.`pt` + JOIN `proyecto` ON `proyecto`.`id` = ptu.`proyecto` +WHERE tep.`descripcion` = 'no pagado' AND `pago`.`fecha` BETWEEN DATE_ADD(CURDATE(), INTERVAL 1 DAY) AND DATE_ADD(CURDATE(), INTERVAL 1 MONTH) + AND tev.`descripcion` IN ('vigente', 'escriturando', 'firmado por inmobiliaria') +GROUP BY `pago`.`fecha`, `proyecto`.`descripcion` +ORDER BY `pago`.`fecha`, `proyecto`.`descripcion`"; + return $this->fetchAsArray($query); + } +} diff --git a/app/src/Repository/Venta/EstadoPago.php b/app/src/Repository/Venta/EstadoPago.php new file mode 100644 index 0000000..406647f --- /dev/null +++ b/app/src/Repository/Venta/EstadoPago.php @@ -0,0 +1,67 @@ +setTable('estado_pago'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'pago' => [ + 'function' => function($data) { + return $this->pagoRepository->fetchById($data['pago']); + } + ], + 'estado' => [ + 'property' => 'tipoEstadoPago', + 'function' => function($data) { + return $this->tipoEstadoPagoRepository->fetchById($data['estado']); + } + ], + 'fecha' => [ + 'function' => function($data) { + return new DateTimeImmutable($data['fecha']); + } + ] + ]; + return $this->parseData(new Model\Venta\EstadoPago(), $data, $map); + } + + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['pago', 'estado', 'fecha'], + [$model->pago->id, $model->tipoEstadoPago->id, $model->fecha->format('Y-m-d')] + ); + return $model; + } + + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['pago', 'estado', 'fecha'], $new_data); + } + + public function fetchByPago(int $pago_id): array + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `pago` = ?"; + return $this->fetchMany($query, [$pago_id]); + } + public function fetchByPagoAndEstado(int $pago_id, int $estado_id): Define\Model + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `pago` = ? AND `estado` = ?"; + return $this->fetchOne($query, [$pago_id, $estado_id]); + } +} diff --git a/app/src/Repository/Venta/EstadoPrecio.php b/app/src/Repository/Venta/EstadoPrecio.php new file mode 100644 index 0000000..c223e30 --- /dev/null +++ b/app/src/Repository/Venta/EstadoPrecio.php @@ -0,0 +1,65 @@ +setTable('estado_precio'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'precio' => [ + 'function' => function($data) { + return $this->precioRepository->fetchById($data['precio']); + } + ], + 'estado' => [ + 'property' => 'tipoEstadoPrecio', + 'function' => function($data) { + return $this->tipoEstadoPrecioRepository->fetchById($data['estado']); + } + ], + 'fecha' => [ + 'function' => function($data) { + return new DateTimeImmutable($data['fecha']); + } + ] + ]; + return $this->parseData(new Model\Venta\EstadoPrecio(), $data, $map); + } + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['precio', 'estado', 'fecha'], + [$model->precio->id, $model->tipoEstadoPrecio->id, $model->fecha->format('Y-m-d')] + ); + return $model; + } + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['precio', 'estado', 'fecha'], $new_data); + } + + public function fetchByPrecio(int $precio_id): array + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `precio` = ?"; + return $this->fetchMany($query, [$precio_id]); + } + public function fetchCurrentByPrecio(int $precio_id): Define\Model + { + $query = "SELECT e1.* +FROM `{$this->getTable()}` e1 JOIN (SELECT MAX(`id`) AS 'id', `precio` FROM `{$this->getTable()}` GROUP BY `precio`) e0 ON e0.`id` = e1.`id` +WHERE e1.`precio` = ?"; + return $this->fetchOne($query, [$precio_id]); + } +} diff --git a/app/src/Repository/Venta/Pago.php b/app/src/Repository/Venta/Pago.php new file mode 100644 index 0000000..ec9b6e6 --- /dev/null +++ b/app/src/Repository/Venta/Pago.php @@ -0,0 +1,73 @@ +setTable('pago'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'valor' => [], + 'banco' => [ + 'function' => function($data) { + if ($data['banco'] === null or $data['banco'] === 0) { + return null; + } + return $this->bancoRepository->fetchById($data['banco']); + } + ], + 'tipo' => [ + 'property' => 'tipoPago', + 'function' => function($data) { + if ($data['tipo'] === null) { + return null; + } + return $this->tipoPagoRepository->fetchById($data['tipo']); + } + ], + 'identificador' => [], + 'fecha' => [ + 'function' => function($data) { + if ($data['fecha'] === null) { + return null; + } + return new DateTimeImmutable($data['fecha']); + } + ], + 'uf' => [], + 'pagador' => [], + 'asociado' => [ + 'function' => function($data) { + if ($data['asociado'] === null) { + return null; + } + return $this->fetchById($data['asociado']); + } + ] + ]; + return $this->parseData(new Model\Venta\Pago(), $data, $map); + } + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['valor', 'banco', 'tipo', 'identificador', 'fecha', 'uf', 'pagador', 'asociado'], + [$model->valor, $model?->banco->id, $model?->tipoPago->id, $model?->identificador, $model?->fecha->format('Y-m-d H:i:s'), $model?->uf, $model?->pagador, $model?->asociado->id] + ); + return $model; + } + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['valor', 'banco', 'tipo', 'identificador', 'fecha', 'uf', 'pagador', 'asociado'], $new_data); + } +} diff --git a/app/src/Repository/Venta/Pie.php b/app/src/Repository/Venta/Pie.php new file mode 100644 index 0000000..37b8d2c --- /dev/null +++ b/app/src/Repository/Venta/Pie.php @@ -0,0 +1,60 @@ +setTable('pie'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'fecha' => [ + 'function' => function($data) { + return new DateTimeImmutable($data['fecha']); + } + ], + 'valor' => [], + 'uf' => [], + 'cuotas' => [], + 'asociado' => [ + 'function' => function($data) { + if ($data['asociado'] === null or $data['asociado'] === 0) { + return null; + } + return $this->fetchById($data['asociado']); + } + ], + 'reajuste' => [ + 'function' => function($data) { + if ($data['reajuste'] === null or $data['reajuste'] === 0) { + return null; + } + return $this->pagoRepository->fetchById($data['reajuste']); + } + ] + ]; + return $this->parseData(new Model\Venta\Pie(), $data, $map); + } + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['fecha', 'valor', 'uf', 'cuotas', 'asociado', 'reajuste'], + [$model->fecha->format('Y-m-d H:i:s'), $model->valor, $model?->uf, $model->cuotas, $model?->asociado->id, $model?->reajuste->id] + ); + return $model; + } + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['fecha', 'valor', 'uf', 'cuotas', 'asociado', 'reajuste'], $new_data); + } +} diff --git a/app/src/Repository/Venta/Precio.php b/app/src/Repository/Venta/Precio.php new file mode 100644 index 0000000..f7bb16d --- /dev/null +++ b/app/src/Repository/Venta/Precio.php @@ -0,0 +1,55 @@ +setTable('precio'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'unidad' => [ + 'function' => function($data) { + return $this->unidadRepository->fetchById($data['unidad']); + } + ], + 'valor' => [] + ]; + return $this->parseData(new Model\Venta\Precio(), $data, $map); + } + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['unidad', 'valor'], + [$model->unidad->id, $model->valor] + ); + return $model; + } + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['unidad', 'valor'], $new_data); + } + + public function fetchByProyecto(int $proyecto_id): array + { + $query = "SELECT a.* +FROM `{$this->getTable()}` a + JOIN (SELECT e1.* FROM `estado_precio` e1 JOIN (SELECT MAX(`id`) AS 'id', `precio` FROM `estado_precio` GROUP BY `precio`) e0 ON e0.`id` = e1.`id`) ep ON ep.`precio` = a.`id` + JOIN `tipo_estado_precio` tep ON tep.`id` = ep.`estado` + JOIN `unidad` ON `unidad`.`id` = a.`unidad` + JOIN `proyecto_tipo_unidad` ptu ON ptu.`id` = `unidad`.`pt` + JOIN `tipo_unidad` tu ON tu.`id` = ptu.`tipo` +WHERE ptu.`proyecto` = ? AND tep.`descripcion` = 'vigente' +ORDER BY tu.`orden`, ptu.`nombre`, `unidad`.`subtipo`, LPAD(`unidad`.`descripcion`, 4, '0')"; + return $this->fetchMany($query, [$proyecto_id]); + } +} diff --git a/app/src/Repository/Venta/Propietario.php b/app/src/Repository/Venta/Propietario.php new file mode 100644 index 0000000..8e0dce6 --- /dev/null +++ b/app/src/Repository/Venta/Propietario.php @@ -0,0 +1,82 @@ +setTable('propietario'); + } + + protected function getKey(): string + { + return 'rut'; + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'dv' => [], + 'nombres' => [], + 'apellido_paterno' => [ + 'property' => 'apellidos', + 'function' => function($data) { + $arr = [ + 'paterno' => $data['apellido_paterno'] + ]; + if ($data['apellido_materno'] !== '') { + $arr['materno'] = $data['apellido_materno']; + } + return $arr; + } + ], + 'direccion' => [ + 'property' => 'datos', + 'function' => function($data) { + $datos = new Model\Venta\Datos(); + if ($data['direccion'] !== null and $data['direccion'] !== 0) { + $datos->direccion = $this->direccionRepository->fetchById($data['direccion']); + } + return $datos; + } + ], + 'representante' => [ + 'function' => function($data) { + if ($data['representante'] === null or $data['representante'] === 0) { + return null; + } + return $this->fetchById($data['representante']); + } + ], + 'otro' => [ + 'function' => function($data) { + if ($data['otro'] === null) { + return null; + } + return $data['otro'] !== 0; + } + ] + ]; + return $this->parseData(new Model\Venta\Propietario(), $data, $map); + } + + public function save(Define\Model $model): Define\Model + { + $model->rut = $this->saveNew( + ['dv', 'nombres', 'apellido_paterno', 'apellido_materno'], + [$model->dv, $model->nombres, $model->apellidos['paterno'], $model->apellidos['materno']] + ); + return $model; + } + + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['dv', 'nombres', 'apellido_paterno', 'apellido_materno'], $new_data); + } +} diff --git a/app/src/Repository/Venta/TipoEstadoPago.php b/app/src/Repository/Venta/TipoEstadoPago.php new file mode 100644 index 0000000..80f8a0b --- /dev/null +++ b/app/src/Repository/Venta/TipoEstadoPago.php @@ -0,0 +1,40 @@ +setTable('tipo_estado_pago'); + } + + public function create(?array $data = null): Define\Model + { + $map = ['descripcion' => []]; + return $this->parseData(new Model\Venta\TipoEstadoPago(), $data, $map); + } + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['descripcion'], + [$model->descripcion] + ); + return $model; + } + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['descripcion'], $new_data); + } + + public function fetchByDescripcion(string $descripcion): Define\Model + { + $query = "SELECT * FROM `{$this->getTable()}` WHERE `descripcion` = ?"; + return $this->fetchOne($query, [$descripcion]); + } +} diff --git a/app/src/Repository/Venta/TipoEstadoPrecio.php b/app/src/Repository/Venta/TipoEstadoPrecio.php new file mode 100644 index 0000000..1955b2e --- /dev/null +++ b/app/src/Repository/Venta/TipoEstadoPrecio.php @@ -0,0 +1,35 @@ +setTable('tipo_estado_precio'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'descripcion' => [] + ]; + return $this->parseData(new Model\Venta\TipoEstadoPrecio(), $data, $map); + } + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['descripcion'], + [$model->descripcion] + ); + return $model; + } + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['descripcion'], $new_data); + } +} diff --git a/app/src/Repository/Venta/TipoPago.php b/app/src/Repository/Venta/TipoPago.php new file mode 100644 index 0000000..dda6865 --- /dev/null +++ b/app/src/Repository/Venta/TipoPago.php @@ -0,0 +1,35 @@ +setTable('tipo_pago'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'descripcion' => [] + ]; + return $this->parseData(new Model\Venta\TipoPago(), $data, $map); + } + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['descripcion'], + [$model->descripcion] + ); + return $model; + } + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['descripcion'], $new_data); + } +} diff --git a/app/src/Repository/Venta/TipoUnidad.php b/app/src/Repository/Venta/TipoUnidad.php new file mode 100644 index 0000000..13474bb --- /dev/null +++ b/app/src/Repository/Venta/TipoUnidad.php @@ -0,0 +1,39 @@ +setTable('tipo_unidad'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'descripcion' => [], + 'orden' => [] + ]; + return $this->parseData(new Model\Venta\TipoUnidad(), $data, $map); + } + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['descripcion', 'orden'], + [$model->descripcion, $model->orden] + ); + return $model; + } + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['descripcion', 'orden'], $new_data); + } +} + + diff --git a/app/src/Repository/Venta/Unidad.php b/app/src/Repository/Venta/Unidad.php new file mode 100644 index 0000000..4783c40 --- /dev/null +++ b/app/src/Repository/Venta/Unidad.php @@ -0,0 +1,47 @@ +setTable('unidad'); + } + + public function create(?array $data = null): Define\Model + { + $map = [ + 'subtipo' => [], + 'piso' => [], + 'descripcion' => [], + 'orientacion' => [], + 'pt' => [ + 'property' => 'proyectoTipoUnidad', + 'function' => function($data) { + return $this->proyectoTipoUnidadRepository->fetchById($data['pt']); + } + ] + ]; + return $this->parseData(new Model\Venta\Unidad(), $data, $map); + } + + public function save(Define\Model $model): Define\Model + { + $model->id = $this->saveNew( + ['subtipo', 'piso', 'descripcion', 'orientacion', 'pt'], + [$model->subtipo, $model->piso, $model->descripcion, $model->orientacion, $model->proyectoTipoUnidad->id] + ); + return $model; + } + + public function edit(Define\Model $model, array $new_data): Define\Model + { + return $this->update($model, ['subtipo', 'piso', 'descripcion', 'orientacion', 'pt'], $new_data); + } +} diff --git a/app/src/Service/Format.php b/app/src/Service/Format.php new file mode 100644 index 0000000..ec9177b --- /dev/null +++ b/app/src/Service/Format.php @@ -0,0 +1,24 @@ +setPattern($format); + return $formatter->format($date); + + } + public function pesos(string $valor): string + { + return '$' . number_format($valor, 0, ',', '.'); + } +} diff --git a/app/src/Service/Login.php b/app/src/Service/Login.php new file mode 100644 index 0000000..175be0d --- /dev/null +++ b/app/src/Service/Login.php @@ -0,0 +1,135 @@ +loadCookie(); + } + + protected string $selector = ''; + protected string $token = ''; + + public function isIn(): bool + { + try { + $login = $this->repository->fetchActiveBySelector($this->selector); + if (!$this->validToken($login)) { + return false; + } + $now = new DateTimeImmutable(); + if ($login->dateTime->add(new DateInterval("PT{$this->max_login_time}H")) > $now) { + return true; + } + } catch (PDOException|EmptyResult) { + } + return false; + } + public function getUser(): Model\User + { + $login = $this->repository->fetchActiveBySelector($this->selector); + if (!$this->validToken($login)) { + throw new Exception('User not found'); + } + return $login->user; + } + + public function login(Model\User $user): bool + { + try { + $login = $this->repository->fetchActiveByUser($user->id); + $this->logout($login->user); + } catch (PDOException|EmptyResult) { + } + + try { + $now = new DateTimeImmutable(); + $login = $this->repository->create([ + 'user_id' => $user->id, + 'time' => $now->format('Y-m-d H:i:s'), + 'status' => 1 + ]); + list('selector' => $selector, 'token' => $token) = $this->generateToken($login); + $login->selector = $selector; + $login->token = password_hash($token, PASSWORD_DEFAULT); + $this->repository->save($login); + $this->saveCookie($selector, $token, $login->dateTime->add(new DateInterval("PT{$this->max_login_time}H"))); + return true; + } catch (PDOException|Exception) { + return false; + } + } + public function logout(Model\User $user): bool + { + $this->removeCookie(); + try { + $logins = $this->repository->fetchByUser($user->id); + } catch (PDOException) { + return true; + } + try { + foreach ($logins as $login) { + $this->repository->edit($login, ['status' => 0]); + } + return true; + } catch (PDOException) { + return false; + } + } + + protected function loadCookie(): void + { + if (!isset($_COOKIE[$this->cookie_name])) { + return; + } + $cookie = $_COOKIE[$this->cookie_name]; + list($this->selector, $this->token) = explode($this->cookie_separator, $cookie); + } + protected function saveCookie(string $selector, string $token, DateTimeInterface $expires): void + { + setcookie( + $this->cookie_name, + implode($this->cookie_separator, [$selector, $token]), + $expires->getTimestamp(), + $this->path, + $this->domain + ); + $this->selector = $selector; + $this->token = $token; + } + protected function removeCookie(): void + { + setcookie( + $this->cookie_name, + '', + (new DateTimeImmutable())->getTimestamp(), + $this->path, + $this->domain + ); + } + + protected function validToken(Model\Login $login): bool + { + return password_verify($this->token, $login->token); + } + protected function generateToken(Model\Login $login) + { + $selector = bin2hex(random_bytes(12)); + $token = bin2hex(random_bytes(20)); + return ['selector' => $selector, 'token' => $token]; + } +} diff --git a/app/src/Service/Ventas/Pago.php b/app/src/Service/Ventas/Pago.php new file mode 100644 index 0000000..f931f38 --- /dev/null +++ b/app/src/Service/Ventas/Pago.php @@ -0,0 +1,31 @@ +tipoEstadoPagoRepository->fetchByDescripcion('depositado'); + $data = [ + 'pago' => $pago->id, + 'estado' => $tipo_estado->id, + 'fecha' => (new DateTimeImmutable())->format('Y-m-d') + ]; + try { + $estado = $this->estadoPagoRepository->create($data); + $this->estadoPagoRepository->save($estado); + return true; + } catch (PDOException) { + return false; + } + } +} diff --git a/app/src/Service/Ventas/Precio.php b/app/src/Service/Ventas/Precio.php new file mode 100644 index 0000000..b03174a --- /dev/null +++ b/app/src/Service/Ventas/Precio.php @@ -0,0 +1,19 @@ +precioRepository->fetchByProyecto($proyecto_id); + foreach ($precios as &$precio) { + $precio->estados = $this->estadoPrecioRepository->fetchByPrecio($precio->id); + $precio->current = $this->estadoPrecioRepository->fetchCurrentByPrecio($precio->id); + } + return $precios; + } +}