Compare commits

...

8 Commits

Author SHA1 Message Date
3580738273 Files 2021-12-25 23:17:15 -03:00
bbee033a8a Files 2021-11-30 22:33:41 -03:00
f589ff960b Files 2021-11-30 18:04:41 -03:00
87323b22d8 Composer 2021-11-30 18:04:27 -03:00
e91fa9a5dd Sample environment files 2021-11-30 18:04:08 -03:00
ef46450dd3 Ignore key 2021-11-30 18:03:57 -03:00
0e1d02e5b7 Docker 2021-11-30 18:02:29 -03:00
1e3018b6b3 Ignore environment and logs 2021-11-30 18:01:49 -03:00
81 changed files with 4865 additions and 0 deletions

2
.adminer.env.sample Normal file
View File

@ -0,0 +1,2 @@
ADMINER_DESIGN=dracula
ADMINER_PLUGINS=dump-json

1
.api.key.sample Normal file
View File

@ -0,0 +1 @@
API_KEY=######################

4
.db.env.sample Normal file
View File

@ -0,0 +1,4 @@
MYSQL_ROOT_PASSWORD=password
MYSQL_USER=user
MYSQL_PASSWORD=password
MYSQL_DATABASE=database

3
.env.sample Normal file
View File

@ -0,0 +1,3 @@
DEBUG=true
BASE_URL=""
MYSQL_HOST=db

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
**/*.env
**/*.key
**/vendor/
**/composer.lock
**/.idea
**/logs/

12
Dockerfile Normal file
View File

@ -0,0 +1,12 @@
FROM php:8-fpm
RUN apt-get update -y && apt-get install -y zip libzip-dev git
RUN docker-php-ext-install pdo pdo_mysql zip
RUN pecl install xdebug-3.1.1 \
&& docker-php-ext-enable xdebug
WORKDIR /code
COPY --from=composer /usr/bin/composer /usr/bin/composer

120
common/Alias/Model.php Normal file
View File

@ -0,0 +1,120 @@
<?php
namespace Incoviba\API\Common\Alias;
use http\Exception\InvalidArgumentException;
use \Model as BaseModel;
use Incoviba\API\Common\Define\Model as ModelInterface;
use Incoviba\API\Common\Factory\Model as ModelFactory;
abstract class Model extends BaseModel implements ModelInterface {
const SELF_KEY = 'self_key';
const CHILD_KEY = 'child_key';
const PARENT_KEY = 'parent_key';
const SIBLING_KEY = 'sibling_key';
const SELF_THROUGH_KEY = 'self_through_key';
const SIBLING_THROUGH_KEY = 'sibling_through_key';
public function getTable(): string {
return static::$_table;
}
protected ModelFactory $factory;
public function setFactory(ModelFactory $factory): ModelInterface {
$this->factory = $factory;
return $this;
}
protected function validateDefinitions(array $definitions, array $minimum_requirements, array $default_values): array {
foreach ($default_values as $key => $val) {
if (!isset($definitions[$key])) {
$definitions[$key] = $val;
}
}
foreach ($minimum_requirements as $key) {
if (!isset($definitions[$key])) {
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
$class = get_called_class();
throw new InvalidArgumentException("Missing {$key} in {$trace[1]['function']} called in {$class}.");
}
}
return $definitions;
}
public function parentOf(string $child_class, array $definitions): bool|array {
$definitions = $this->validateDefinitions(
$definitions,
[Model::CHILD_KEY, Model::SELF_KEY],
[Model::SELF_KEY => 'id']
);
$where = [[$definitions[Model::CHILD_KEY], $this->{$definitions[Model::SELF_KEY]}]];
return $this->factory->find($child_class)->where($where)->many();
}
public function childOf(string $parent_class, array $definitions): bool|ModelInterface {
$definitions = $this->validateDefinitions(
$definitions,
[Model::PARENT_KEY, Model::SELF_KEY],
[Model::PARENT_KEY => 'id']
);
$where = [[$definitions[Model::PARENT_KEY], $this->{$definitions[Model::SELF_KEY]}]];
return $this->factory->find($parent_class)->where($where)->one();
}
public function siblingOf(string $sibling_class, string $connecting_table, array $definitions): ?array {
$definitions = $this->validateDefinitions(
$definitions,
[Model::SIBLING_KEY, Model::SIBLING_THROUGH_KEY, Model::SELF_THROUGH_KEY, Model::SELF_KEY],
[Model::SIBLING_KEY => 'id', Model::SELF_KEY => 'id']
);
$sibling_table = (new $sibling_class())->getTable();
$joins = [
[
$connecting_table,
"{$connecting_table}.{$definitions[Model::SIBLING_THROUGH_KEY]}",
"{$sibling_table}.{$definitions[Model::SIBLING_KEY]}"
]
];
$where = [
[$definitions[Model::SIBLING_KEY], "{$connecting_table}.{$definitions[Model::SIBLING_THROUGH_KEY]}"],
["{$connecting_table}.{$definitions[Model::SELF_THROUGH_KEY]}", $this->{$definitions[Model::SELF_KEY]}]
];
return $this->factory
->find($sibling_class)
->join($joins)
->select("{$sibling_table}.*")
->where($where)
->many();
}
public function toArray(): array {
return $this->as_array();
}
protected static function parseInput($input): array {
return array_intersect_key((array) $input, array_combine(static::$fields, static::$fields));
}
public static function add(ModelFactory $factory, $input): bool|ModelInterface {
$data = static::parseInput($input);
$class = get_called_class();
if (method_exists($class, 'find')) {
$obj = static::find($factory, $input);
} else {
$where = $data;
array_walk($where, function(&$item, $key) {
$item = [$key, $item];
});
$where = array_values($where);
$obj = $factory->find($class)->where($where)->one();
}
if ($obj === false or $obj === null) {
$obj = $factory->create($class, $data);
}
return $obj;
}
public function edit($input): ?array {
$data = static::parseInput($input);
foreach (static::$fields as $field) {
if ($this->{$field} != $data[$field]) {
$this->{$field} = $data[$field];
}
}
return $this->save();
}
}

View File

@ -0,0 +1,82 @@
<?php
namespace Incoviba\API\Common\Controller;
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;
class Auth {
use Json;
public function generate(Request $request, Response $response, Service $service): Response {
$key = $service->generate();
return $this->withJson($response, compact('key'));
}
public function login(Request $request, Response $response, Service $service, Factory $factory): Response {
$post = json_decode($request->getBody());
$user = $factory->find(User::class)->where([['name', $post->name]])->one();
$output = [
'login' => false,
'token' => ''
];
if ($user->enabled == 0) {
$this->withJson($response, $output);
}
if ($user->validate($post->password)) {
$token = $service->generateToken();
$status = $user->setToken($token->selector, $token->token);
if ($status['logged_in']) {
$output['login'] = true;
$output['token'] = $token->full;
$output['expires'] = $status['expires'];
}
}
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 {
$post = json_decode($request->getBody());
if (!$this->getLogin($post, $factory)) {
return $this->withJson($response, ['token' => $post->token, 'error' => 'Not authorized'], 401);
}
return $this->withJson($response, ['token' => $post->token, 'status' => 'Authorized']);
}
public function user(Request $request, Response $response, Factory $factory): Response {
$post = json_decode($request->getBody());
$login = $this->getLogin($post, $factory);
if (!$login) {
return $this->withJson($response, ['token' => $post->token, 'error' => 'Not authorized'], 401);
}
$output = [
'token' => $post->token,
'user' => $login->user()->name
];
return $this->withJson($response, $output);
}
public function logout(Request $request, Response $response, Factory $factory): 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();
$output = [
'token' => $post->token,
'logout' => false
];
if ($login !== false) {
$output['logout'] = $login->user()->logout();
} else {
$output['logout'] = true;
}
return $this->withJson($response, $output);
}
}

View File

@ -0,0 +1,80 @@
<?php
namespace Incoviba\API\Common\Controller;
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\Common\Banco;
class Bancos {
use Json;
public function __invoke(Request $request, Response $response, Factory $factory): Response {
$bancos = $factory->find(Banco::class)->array();
$url = '' . $request->getUri();
array_walk($bancos, function (&$item) use ($url) {
$item['link'] = [
'rel' => 'banco',
'title' => $item['nombre'],
'href' => str_replace('/bancos', "/banco/{$item['id']}", $url)
];
});
return $this->withJson($response, compact('bancos'));
}
public function show(Request $request, Response $response, Factory $factory, $banco_id): Response {
$banco = $factory->find(Banco::class)->one($banco_id);
$output = [
'input' => $banco_id,
'banco' => $banco->toArray(),
'link' => [
'rel' => 'bancos',
'title' => 'Bancos',
'href' => str_replace("/banco/{$banco_id}", '/bancos', $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('bancos', $post)) {
$output['bancos'] = [];
foreach ($post['bancos'] as $input) {
$banco = Banco::add($factory, $input);
$banco []= [
'banco' => $banco->toArray(),
'created' => $banco->is_new() ? $banco->save() : false
];
}
} elseif (in_array('banco', $post)) {
$banco = Banco::add($factory, $post);
$output['banco'] = $banco;
$output['created'] = $banco->is_new() ? $banco->save() : false;
}
return $this->withJson($response, $output);
}
public function edit(Request $request, Response $response, Factory $factory, $banco_id): Response {
$post = $request->getParsedBody();
$input = compact('banco_id', 'post');
$banco = $factory->find(Banco::class)->one($banco_id);
$output = [
'input' => $input,
'banco' => $banco->toArray()
];
$output['edited'] = $banco->edit($post);
$output['changes'] = $banco->toArray();
return $this->withJson($response, $output);
}
public function delete(Request $request, Response $response, Factory $factory, $banco_id): Response {
$banco = $factory->find(Banco::class)->one($banco_id);
$output = [
'input' => $banco_id,
'banco' => $banco->toArray()
];
$output['deleted'] = $banco->delete();
return $this->withJson($response, $output);
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace Incoviba\API\Common\Controller;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Incoviba\API\Common\Define\Controller\Json;
class Base {
use Json;
public function __invoke(Request $request, Response $response): Response {
return $this->withJson($response, [
'api' => [
'version' => '1.0.0'
]
]);
}
public function info(Request $request, Response $response): Response {
phpinfo();
return $response;
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace Incoviba\API\Common\Controller;
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\Admin\Config;
class Configs {
use Json;
public function get(Request $request, Response $response, Factory $factory, $config_name): Response {
$config = $factory->find(Config::class)->where((['name', $config_name]))->one();
$output = [
'name' => $config_name,
'valid' => $config !== false,
'value' => $config->value
];
return $this->withJson($response, $output);
}
public function set(Request $request, Response $response, Factory $factory): Response {
$post = $request->getParsedBody();
$config = $factory->find(Config::class)->where([['name', $post['name']]])->one();
if (!$config) {
$config = Config::add($factory, $post);
} else {
$config->edit($post);
}
$output = [
'input' => $post,
'config' => null
];
if ($config !== false) {
$config->save();
$output['config'] = [
'name' => $config->name,
'value' => $config->value
];
}
return $this->withJson($response, $output);
}
}

View File

@ -0,0 +1,166 @@
<?php
namespace Incoviba\API\Common\Controller;
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\Factory\Model as Factory;
use Incoviba\Inmobiliaria\Inmobiliaria;
class Inmobiliarias {
use Json;
public function __invoke(Request $request, Response $response, Factory $factory): Response {
$inmobiliarias = $factory->find(Inmobiliaria::class)->array();
$base_url = str_replace('/inmobiliarias', '{URL}', $request->getUri());
array_walk($inmobiliarias, function (&$item) use ($base_url) {
$link = [
'rel' => 'inmobiliaria',
'title' => $item['abreviacion'],
'href' => str_replace('{URL}',"/inmobiliaria/{$item['rut']}", $base_url)
];
$item['link'] = $link;
});
return $this->withJson($response, compact('inmobiliarias'));
}
protected function getInmobiliaria(Factory $factory, $inmobiliaria_rut): bool|Inmobiliaria {
return $factory->find(Inmobiliaria::class)->where([['rut', $inmobiliaria_rut]])->one();
}
public function show(Request $request, Response $response, Factory $factory, $inmobiliaria_rut): Response {
$inmobiliaria = $this->getInmobiliaria($factory, $inmobiliaria_rut);
$output = [
'input' => $inmobiliaria_rut,
'inmobiliaria' => $inmobiliaria->toArray(),
'link' => [
'rel' => 'inmobiliarias',
'title' => 'Inmobiliarias',
'href' => str_replace("/inmobiliaria/{$inmobiliaria_rut}", '/inmobiliarias', $request->getUri())
]
];
$base_url = str_replace("/inmobiliaria/{$inmobiliaria_rut}", "/inmobiliaria/{$inmobiliaria_rut}{URL}", $request->getUri());
$output['inmobiliaria']['links'] = [
[
'rel' => 'banco',
'title' => $inmobiliaria->banco()->nombre,
'href' => str_replace("/inmobiliaria/{$inmobiliaria_rut}", "/banco/{$inmobiliaria->banco}", $request->getUri())
],
[
'rel' => 'sociedad',
'title' => $inmobiliaria->sociedad()->descripcion,
'href' => str_replace("/inmobiliaria/{$inmobiliaria_rut}", "/sociedad/{$inmobiliaria->sociedad}", $request->getUri())
],
[
'rel' => 'proyectos',
'title' => 'Proyectos',
'href' => str_replace('{URL}', '/proyectos', $base_url)
]
];
return $this->withJson($response, $output);
}
public function add(Request $request, Response $response, Factory $factory): Response {
$post = $request->getParsedBody();
$output = [
'input' => $post
];
if (in_array('inmobiliarias', $post)) {
$output['inmobiliarias'] = [];
foreach ($post['inmobiliarias'] as $input) {
$inmobiliaria = Inmobiliaria::add($factory, $input);
$inmobiliarias []= [
'inmobiliaria' => $inmobiliaria->toArray(),
'created' => $inmobiliaria->is_new() ? $inmobiliaria->save() : false
];
}
} elseif (in_array('inmobiliaria', $post)) {
$inmobiliaria = Inmobiliaria::add($factory, $post);
$output['inmobiliaria'] = $inmobiliaria;
$output['created'] = $inmobiliaria->is_new() ? $inmobiliaria->save() : false;
}
return $this->withJson($response, $output);
}
public function edit(Request $request, Response $response, Factory $factory, $inmobiliaria_rut): Response {
$post = $request->getParsedBody();
$input = compact('inmobiliaria_rut', 'post');
$inmobiliaria = $this->getInmobiliaria($factory, $inmobiliaria_rut);
$output = [
'input' => $input,
'inmobiliaria' => $inmobiliaria->toArray()
];
$output['edited'] = $inmobiliaria->edit($post);
$output['changes'] = $inmobiliaria->toArray();
return $this->withJson($response, $output);
}
public function delete(Request $request, Response $response, Factory $factory, $inmobiliaria_rut): Response {
$inmobiliaria = $this->getInmobiliaria($factory, $inmobiliaria_rut);
$output = [
'input' => $inmobiliaria_rut,
'inmobiliaria' => $inmobiliaria->toArray()
];
$output['deleted'] = $inmobiliaria->delete();
return $this->withJson($response, $output);
}
public function proyectos(Request $request, Response $response, Factory $factory, $inmobiliaria_rut): Response {
$inmobiliaria = $this->getInmobiliaria($factory, $inmobiliaria_rut);
$proyectos = $inmobiliaria?->proyectos();
$base_url = str_replace("/inmobiliaria/{$inmobiliaria_rut}/proyectos", '{URL}', $request->getUri());
$output = [
'input' => $inmobiliaria_rut,
'inmobiliaria' => $inmobiliaria->toArray(),
'proyectos' => ($proyectos) ? array_map(function ($item) use ($base_url) {
$arr = $item->toArray();
$arr['link'] = [
'rel' => 'proyecto',
'title' => $item->descripcion,
'href' => str_replace('{URL}', "/proyecto/{$item->id}", $base_url)
];
return $arr;
}, $proyectos) : []
];
$output['inmobiliaria']['link'] = [
'rel' => 'inmobiliaria',
'title' => $inmobiliaria->abreviacion,
'href' => str_replace('{URL}', "/inmobiliaria/{$inmobiliaria_rut}", $base_url)
];
return $this->withJson($response, $output);
}
public function sociedad(Request $request, Response $response, Factory $factory, $inmobiliaria_rut): Response {
$inmobiliaria = $this->getInmobiliaria($factory, $inmobiliaria_rut);
$base_url = str_replace("/inmobiliaria/{$inmobiliaria_rut}/sociedad", '{URL}', $request->getUri());
$output = [
'input' => $inmobiliaria_rut,
'inmobiliaria' => $inmobiliaria->toArray(),
'sociedad' => $inmobiliaria->sociedad()->toArray()
];
$output['inmobiliaria']['link'] = [
'rel' => 'inmobiliaria',
'title' => $inmobiliaria->abreviacion,
'href' => str_replace('{URL}', "/inmobiliaria/{$inmobiliaria_rut}", $base_url)
];
$output['sociedad']['link'] = [
'rel' => 'tipo_sociedad',
'title' => $inmobiliaria->sociedad()->descripcion,
'href' => str_replace('{URL}', "/tipos/sociedad/{$inmobiliaria->sociedad}", $base_url)
];
return $this->withJson($response, $output);
}
public function banco(Request $request, Response $response, Factory $factory, $inmobiliaria_rut): Response {
$inmobiliaria = $this->getInmobiliaria($factory, $inmobiliaria_rut);
$base_url = str_replace("/inmobiliaria/{$inmobiliaria_rut}/banco", '{URL}', $request->getUri());
$output = [
'input' => $inmobiliaria_rut,
'inmobiliaria' => $inmobiliaria->toArray(),
'banco' => $inmobiliaria->banco()->toArray()
];
$output['inmobiliaria']['link'] = [
'rel' => 'inmobiliaria',
'title' => $inmobiliaria->abreviacion,
'href' => str_replace('{URL}', "/inmobiliaria/{$inmobiliaria_rut}", $base_url)
];
$output['banco']['link'] = [
'rel' => 'banco',
'title' => $inmobiliaria->banco()->nombre,
'href' => str_replace('{URL}', "/banco/{$inmobiliaria->banco}", $base_url)
];
return $this->withJson($response, $output);
}
}

View File

@ -0,0 +1,91 @@
<?php
namespace Incoviba\API\Common\Controller;
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\Factory\Model as Factory;
use Incoviba\Venta\Propietario;
class Propietarios {
use Json;
public function __invoke(Request $request, Response $response, Factory $factory): Response {
$propietarios = $factory->find(Propietario::class)->array();
$base_url = str_replace('/propietarios', '{URL}', $request->getUri());
array_walk($propietarios, function (&$item) use ($base_url) {
$link = [
'rel' => 'propietario',
'title' => implode(' ', [$item['nombres'], $item['apellido_paterno'], $item['apellido_materno']]),
'href' => str_replace('{URL}', "/propietario/{$item['rut']}", $base_url)
];
$item['link'] = $link;
});
return $this->withJson($response, compact('propietarios'));
}
protected function get(Factory $factory, string $class, $rut) {
return $factory->find($class)->where([['rut', $rut]])->one();
}
public function show(Request $request, Response $response, Factory $factory, $propietario_rut): Response {
$propietario = $this->get($factory, Propietario::class, $propietario_rut);
$output = [
'input' => $propietario_rut,
'propietario' => $propietario->toArray(),
'link' => [
'rel' => 'propietarios',
'title' => 'Propietarios',
'href' => str_replace("/propietario/{$propietario_rut}", '/propietarios', $request->getUri())
]
];
$output['links'] = [
[
'rel' => 'direccion',
'title' => $propietario->direccion()->calle,
'href' => str_replace("/propietario/{$propietario_rut}", "/direccion/{$propietario->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('propietarios', $post)) {
$output['propietarios'] = [];
foreach ($post['propietarios'] as $input) {
$propietario = Propietario::add($factory, $input);
$propietario []= [
'propietario' => $propietario->toArray(),
'created' => $propietario->is_new() ? $propietario->save() : false
];
}
} elseif (in_array('propietario', $post)) {
$propietario = Propietario::add($factory, $post);
$output['propietario'] = $propietario;
$output['created'] = $propietario->is_new() ? $propietario->save() : false;
}
return $this->withJson($response, $output);
}
public function edit(Request $request, Response $response, Factory $factory, $propietario_rut): Response {
$post = $request->getParsedBody();
$input = compact('propietario_rut', 'post');
$propietario = $this->get($factory, Propietario::class, $propietario_rut);
$output = [
'input' => $input,
'propietario' => $propietario->toArray()
];
$output['edited'] = $propietario->edit($post);
$output['changes'] = $propietario->toArray();
return $this->withJson($response, $output);
}
public function delete(Request $request, Response $response, Factory $factory, $propietario_rut): Response {
$propietario = $this->get($factory, Propietario::class, $propietario_rut);
$output = [
'input' => $propietario_rut,
'propietario' => $propietario->toArray()
];
$output['deleted'] = $propietario->delete();
return $this->withJson($response, $output);
}
}

View File

@ -0,0 +1,93 @@
<?php
namespace Incoviba\API\Common\Controller;
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\Factory\Model as Factory;
use Incoviba\Proyecto\Proyecto;
class Proyectos {
use Json;
public function __invoke(Request $request, Response $response, Factory $factory): Response {
$proyectos = $factory->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;
}
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);
}
}

View File

@ -0,0 +1,31 @@
<?php
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;
class Cierres {
use Json;
public function __invoke(Request $request, Response $response, Factory $factory): Response {
$proyectos = $factory->find(Proyecto::class)->many();
$cierres = [];
foreach ($proyectos as $proyecto) {
if (count($proyecto->cierres()) == 0) {
continue;
}
$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
];
}
return $this->withJson($response, compact('cierres'));
}
}

View File

@ -0,0 +1,63 @@
<?php
namespace Incoviba\API\Common\Controller\Proyectos;
use Incoviba\Proyecto\Proyecto;
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\Factory\Model as Factory;
class Cuotas {
use Json;
public function __invoke(Request $request, Response $response, Factory $factory): Response {
$proyectos = $factory->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();
$dias = [];
foreach ($proyectos as $proyecto) {
foreach ($proyecto->cuotasMes() as $cuota) {
$f = $cuota->pago()->fecha();
if ($f->isoWeekday() == 6 or $f->isoWeekDay() == 7) {
$f = $f->copy()->addDays(2)->startOfWeek();
}
$dia = $f->format('Y-m-d');
if (!isset($dias[$dia])) {
$dias[$dia] = ['dia' => $dia, 'proyectos' => [$proyecto->descripcion => ['proyecto' => $proyecto->descripcion, 'cantidad' => 0]]];
}
if (!isset($dias[$dia]['proyectos'][$proyecto->descripcion])) {
$dias[$dia]['proyectos'][$proyecto->descripcion] = ['proyecto' => $proyecto->descripcion, 'cantidad' => 0];
}
$dias[$dia]['proyectos'][$proyecto->descripcion]['cantidad'] ++;
}
}
uksort($dias, function($a, $b) {
return strcmp($a, $b);
});
return $this->withJson($response, ['proyecto' => $proyecto->toArray(), 'dias' => $dias]);
}
public function hoy(Request $request, Response $response, Factory $factory): Response {
$proyectos = $factory->find(Proyecto::class)->many();
$hoy = 0;
foreach ($proyectos as $proyecto) {
$hoy += count($proyecto->cuotasHoy());
}
return $this->withJson($response, ['hoy' => $hoy]);
}
public function pendientes(Request $request, Response $response, Factory $factory): Response {
$proyectos = $factory->find(Proyecto::class)->many();
$pendientes = 0;
foreach ($proyectos as $proyecto) {
$pendientes += count($proyecto->cuotasPendientes());
}
return $this->withJson($response, ['pendientes' => $pendientes]);
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace Incoviba\API\Common\Controller;
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\Factory\Model as Factory;
use Incoviba\Inmobiliaria\TipoSociedad;
class Sociedades {
use Json;
public function __invoke(Request $request, Response $response, Factory $factory): Response {
$sociedades = $factory->find(TipoSociedad::class)->array();
$base_url = str_replace('/sociedades', '{URL}', $request->getUri());
array_walk($sociedades, function (&$item) use ($base_url) {
$link = [
'rel' => 'sociedad',
'title' => $item['descripcion'],
'href' => str_replace('{URL}', "/sociedad/{$item['id']}", $base_url)
];
$item['link'] = $link;
});
return $this->withJson($response, compact('sociedades'));
}
public function show(Request $request, Response $response, Factory $factory, $sociedad_id): Response {
$sociedad = $factory->find(TipoSociedad::class)->one($sociedad_id);
$output = [
'input' => $sociedad_id,
'sociedad' => $sociedad->toArray(),
'link' => [
'rel' => 'sociedades',
'title' => 'Sociedades',
'href' => str_replace("/sociedad/{$sociedad_id}", '/sociedades', $request->getUri())
]
];
return $this->withJson($response, $output);
}
}

View File

@ -0,0 +1,155 @@
<?php
namespace Incoviba\API\Common\Controller;
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\Factory\Model as Factory;
use Incoviba\Venta\Venta;
class Ventas {
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())
];
}
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);
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace Incoviba\API\Common\Define\Controller;
use Psr\Http\Message\ResponseInterface as Response;
trait Json {
public function withJson(Response $response, $data, $status = 200): Response {
$response->getBody()->write(json_encode($data, JSON_UNESCAPED_SLASHES));
return $response
->withStatus($status)
->withHeader('content-type', 'application/json');
}
}

62
common/Define/Model.php Normal file
View File

@ -0,0 +1,62 @@
<?php
namespace Incoviba\API\Common\Define;
use Incoviba\API\Common\Factory\Model as ModelFactory;
interface Model {
/**
* @return string
*/
public function getTable(): string;
/**
* @param ModelFactory $factory
* @return Model
*/
public function setFactory(ModelFactory $factory): Model;
/**
* Get all children models of class {$child_class}
* @param string $child_class Class of child model
* @param array $definitions array of conditions for connecting to the child table
* @return array|null
*/
public function parentOf(string $child_class, array $definitions): bool|array;
/**
* Get parent model of class {$parent_class}
* @param string $parent_class Class of parent model
* @param array $definitions array of conditions for connecting to the parent table
* @return Model|null
*/
public function childOf(string $parent_class, array $definitions): bool|Model;
/**
* Get all siblings of class {$sibling_class}
* @param string $sibling_class Class of sibling model
* @param string $connecting_table table connecting both models
* @param array $definitions array of conditions for connecting to the sibling and connecting tables
* @return array|null
*/
public function siblingOf(string $sibling_class, string $connecting_table, array $definitions): ?array;
/**
* @return array
*/
public function toArray(): array;
/**
* Add a new model of this type to the database, parsing {$input} data
* @param ModelFactory $factory Factory object for connecting to the database
* @param array $input Input data
* @return Model|null
*/
public static function add(ModelFactory $factory, array $input): bool|Model;
/**
* Edit current model parsing {$input} data
* @param array $input Input data
* @return array|null
*/
public function edit(array $input): ?array;
}

404
common/Factory/Model.php Normal file
View File

@ -0,0 +1,404 @@
<?php
namespace Incoviba\API\Common\Factory;
use InvalidArgumentException;
use ORM;
use Incoviba\API\Common\Alias\Model as BaseModel;
use Incoviba\API\Common\Define\Model as ModelInterface;
class Model {
public static function for(string $class): Model {
$factory = new Model();
return $factory->find($class);
}
protected function reset(): Model {
$resets = ['columns', 'joins', 'conditions', 'groups', 'orders', 'having', 'limit', 'offset'];
foreach ($resets as $r) {
$this->{$r} = null;
}
return $this;
}
public function create(string $model_class, array $data = null): bool|ModelInterface {
// Check if it already exists
if ($data !== null) {
$model = $this->find($model_class);
foreach ($data as $f => $v) {
$model = $model->where([[$f, $v]]);
}
$model = $model->one();
if ($model !== false and $model !== null) {
return $model;
}
}
$model = BaseModel::factory($model_class)->create($data);
if (is_a($model, \ORMWrapper::class)) {
$model = $model->find_one();
}
$model->setFactory($this);
return $model;
}
protected string $class;
public function find(string $class): Model {
$this->reset();
if (!class_exists($class)) {
throw new InvalidArgumentException("Model {$class} not found.");
}
$this->class = $class;
return $this;
}
protected ?array $columns;
public function select($columns): Model {
if (!is_array($columns)) {
$columns = [$columns];
}
foreach ($columns as $c) {
$this->addColumn($c);
}
return $this;
}
protected function addColumn($column) {
$col = [
'table' => '',
'column' => $column
];
if (is_array($column)) {
$col['table'] = $column['table'] ?? $column[0];
$col['column'] = $column['column'] ?? $column[1];
}
$this->columns []= $col;
}
protected function parseColumns(ORM $orm): ORM {
if ($this->columns === null) {
return $orm;
}
foreach ($this->columns as $column) {
$orm = $orm->select("{$column['table']}.{$column['column']}");
}
return $orm;
}
protected ?array $joins;
public function join($joins): Model {
foreach ($joins as $join) {
$this->addJoin($join);
}
return $this;
}
protected function addJoin($join) {
$map = [
'table' => ['table', 't', 0],
'from' => ['from', 'f', 1],
'to' => ['to', 2],
'operator' => ['operator', 'op', 'o', 3],
'type' => 'type',
'alias' => 'alias',
'params' => ['parameters', 'params']
];
$defaults = ['operator' => '=', 'type' => 'inner'];
$required = ['table', 'from', 'to', 'operator', 'type'];
$j = [];
foreach ($join as $key => $val) {
$k = -1;
foreach ($map as $i => $m) {
if (is_array($m)) {
if (in_array($key, $m)) {
$k = $i;
break;
}
continue;
}
if ($m == $key) {
$k = $i;
}
}
$j[$k] = $val;
}
foreach ($defaults as $key => $val) {
if (!isset($j[$key])) {
$j[$key] = $val;
}
}
foreach ($required as $key) {
if (!isset($j[$key])) {
throw new InvalidArgumentException("Missing {$key} when joining in " . get_class());
}
}
$this->joins []= (object) $j;
}
protected function parseJoins(ORM $orm): ORM {
if ($this->joins === null) {
return $orm;
}
foreach ($this->joins as $join) {
$method = match(strtolower($join->type)) {
'raw' => 'rawJoin',
'inner' => 'innerJoin',
'left', 'left outer', 'left_outer', 'leftouter' => 'leftOuterJoin',
'right', 'right outer', 'right_outer', 'rightouter' => 'rightOuterJoin',
'full', 'full outer', 'full_outer', 'fullouter', 'outer' => 'fullOuterJoin'
};
if (strtolower($join->type) == 'raw') {
if (isset($join->params)) {
if (isset($join->alias)) {
$orm = $orm->{$method}($join->table, [$join->from, $join->operator, $join->to], $join->alias, $join->params);
} else {
$orm = $orm->{$method}($join->table, [$join->from, $join->operator, $join->to], $join->params);
}
} else {
if (isset($join->alias)) {
$orm = $orm->{$method}($join->table, [$join->from, $join->operator, $join->to], $join->alias);
} else {
$orm = $orm->{$method}($join->table, [$join->from, $join->operator, $join->to]);
}
}
} elseif (isset($join->alias)) {
$orm = $orm->{$method}($join->table, [$join->from, $join->operator, $join->to], $join->alias);
} else {
$orm = $orm->{$method}($join->table, [$join->from, $join->operator, $join->to]);
}
}
return $orm;
}
protected ?array $conditions;
public function where(array $conditions): Model {
foreach ($conditions as $condition) {
$this->addCondition($condition);
}
return $this;
}
protected function addCondition(array $condition) {
$map = [
'column' => ['column', 'field', 'col', 'c', 'f', 0],
'value' => ['value', 'val', 'v', 1],
'operator' => ['operator', 'op', 'o', 'type', 't', 2]
];
$defaults = ['operator' => '=', 'type' => 'eq'];
$required = ['column', 'value', 'operator'];
$c = [];
foreach ($condition as $key => $val) {
$k = -1;
foreach ($map as $i => $m) {
if (is_array($m)) {
if (in_array($key, $m)) {
$k = $i;
break;
}
continue;
}
if ($key == $m) {
$k = $i;
}
}
$c[$k] = $val;
}
foreach ($defaults as $key => $val) {
if (!isset($c[$key])) {
$c[$key] = $val;
}
}
foreach ($required as $key) {
if (!isset($c[$key])) {
throw new InvalidArgumentException("Missing {$key} when adding conditions in " . get_class());
}
}
$this->conditions []= (object) $c;
}
protected function parseConditions(ORM $orm): ORM {
if ($this->conditions === null) {
return $orm;
}
foreach ($this->conditions as $condition) {
$method = match(strtolower($condition->operator)) {
'', '=', 'eq', 'equal', 'equals' => 'where',
'<', 'lt', 'less than', 'less_than', 'lessthan' => 'whereLt',
'<=', 'lte', 'less equal', 'less equals', 'less_equal', 'less_equals', 'lessequal', 'lessequals',
'less than equal', 'less than equals', 'less_than_equal', 'less_than_equals', 'lessthanequal',
'lessthanequals' => 'whereLte',
'>', 'gt', 'greater than', 'greater_than', 'greaterthan' => 'whereGt',
'>=', 'gte', 'greater equal', 'greater equals', 'greater_equal', 'greater_equals', 'greaterequal',
'greaterequals', 'greater than equal', 'greater than equals', 'greater_than_equal', 'greater_than_equals',
'greaterthanequal', 'greaterthanequals' => 'whereGte',
'!=', 'not equal', 'not equals', 'not_equal', 'not_equals', 'notequal', 'notequals' => 'whereNotEqual',
'like' => 'whereLike',
'not like', 'not_like', 'notlike' => 'whereNotLike',
'in' => 'whereIn',
'not in', 'not_in', 'notin' => 'whereNotIn',
'raw' => 'raw'
};
$orm = $orm->{$method}($condition->column, $condition->value);
}
return $orm;
}
protected ?array $groups;
public function group($groups): Model {
if (!is_array($groups)) {
$groups = [$groups];
}
foreach ($groups as $group) {
$this->addGroup($group);
}
return $this;
}
protected function addGroup(string $group) {
$this->groups []= $group;
}
protected function parseGroups(ORM $orm): ORM {
if ($this->groups === null) {
return $orm;
}
foreach ($this->groups as $group) {
if (str_contains($group, '(')) {
$orm = $orm->groupByExpr($group);
continue;
}
$orm = $orm->groupBy($group);
}
return $orm;
}
protected ?array $orders;
public function order($orders): Model {
if (!is_array($orders)) {
$orders = [$orders];
}
foreach ($orders as $order) {
$this->addOrder($order);
}
return $this;
}
protected function addOrder($order) {
$map = [
'column' => ['column', 'col', 'c', 0],
'direction' => ['direction', 'dir', 'd', 1]
];
if (!is_array($order)) {
$order = [$order];
}
$defaults = ['direction' => 'asc'];
$required = ['column', 'direction'];
$o = [];
foreach ($order as $key => $val) {
/*$k = match (strtolower($key)) {
'column', 'col', 'c', 0 => 'column',
'direction', 'dir', 'd', 1 => 'direction'
};*/
$k = -1;
foreach ($map as $i => $m) {
if (is_array($m)) {
if (in_array($key, $m)) {
$k = $i;
break;
}
continue;
}
if ($key == $m) {
$k = $i;
}
}
$o[$k] = $val;
}
foreach ($defaults as $key => $val) {
if (!isset($o[$key])) {
$o[$key] = $val;
}
}
foreach ($required as $key) {
if (!isset($o[$key])) {
throw new InvalidArgumentException("Missing {$key} in order.");
}
}
$this->orders []= (object) $o;
}
protected function parseOrders(ORM $orm): ORM {
if ($this->orders === null) {
return $orm;
}
foreach ($this->orders as $order) {
if (str_contains($order->column, '(')) {
$orm = $orm->orderByExpr($order->column);
continue;
}
$method = match (strtolower($order->direction)) {
'ascending', 'asc', '' => 'orderByAsc',
'descending', 'desc' => 'orderByDesc'
};
$orm = $orm->{$method}($order->column);
}
return $orm;
}
protected ?int $limit;
public function limit(int $limit): Model {
$this->limit = $limit;
return $this;
}
protected function parseLimit(ORM $orm): ORM {
if ($this->limit === null) {
return $orm;
}
return $orm->limit($this->limit);
}
protected ?int $offset;
public function offset(int $offset): Model {
$this->offset = $offset;
return $this;
}
protected function parseOffset(ORM $orm): ORM {
if ($this->offset === null) {
return $orm;
}
return $orm->offset($this->offset);
}
public function build(): ORM {
$orm = BaseModel::factory($this->class);
$methods = [
'columns',
'joins',
'conditions',
'groups',
'orders',
'limit',
'offset'
];
foreach ($methods as $m) {
$method = 'parse' . ucfirst($m);
$orm = $this->{$method}($orm);
}
return $orm;
}
public function one(?int $id = null): bool|ModelInterface {
$result = $this->build()->find_one($id);
if ($result !== false) {
$result->setFactory($this);
}
return $result;
}
public function many(): bool|array {
$results = $this->build()->find_many();
if ($results !== false) {
foreach ($results as &$result) {
$result->setFactory($this);
}
}
return $results;
}
public function array(): ?array {
$results = $this->many();
if ($results === false) {
return null;
}
return array_map(function($item) {
return $item->toArray();
}, $results);
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace Incoviba\API\Common\Middleware;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as Handler;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ResponseFactoryInterface as Factory;
use Incoviba\API\Common\Service\Auth as Service;
class Auth {
protected $service;
protected $factory;
protected $exceptions;
public function __construct(Service $service, Factory $factory, array $exception_routes) {
$this->service = $service;
$this->factory = $factory;
$this->exceptions = $exception_routes;
}
public function __invoke(Request $request, Handler $handler): Response {
$path = $request->getUri()->getPath();
if (in_array($path, $this->exceptions) or $this->service->isValid($request)) {
return $handler->handle($request);
}
$response = $this->factory->createResponse();
$response->getBody()->write(json_encode(['message' => 'Not authorized.']));
return $response
->withStatus(401) // unauthorized
->withHeader('content-type', 'application/json');
}
}

60
common/Service/Auth.php Normal file
View File

@ -0,0 +1,60 @@
<?php
namespace Incoviba\API\Common\Service;
use Psr\Http\Message\ServerRequestInterface as Request;
class Auth {
protected string $key;
public function __construct(string $key) {
$this->key = $key;
}
public function isValid(Request $request): bool {
$api_key = $this->getRequestKey($request);
if ($this->key == $api_key) {
return true;
}
return false;
}
protected function getRequestKey(Request $request) {
if ($request->hasHeader('Authorization')) {
return $this->getKeyFromHeader($request);
} elseif ($request->getParsedBody() !== null and in_array('API_KEY', $request->getParsedBody())) {
return $request->getParsedBody()['API_KEY'];
} elseif ($request->getQueryParams() !== null and in_array('API_KEY', array_keys($request->getQueryParams()))) {
return $request->getQueryParams()['API_KEY'];
}
return '';
}
protected function getKeyFromHeader(Request $request) {
$api_key = $request->getHeader('Authorization');
if (is_array($api_key)) {
$api_key = $api_key[0];
}
if (str_contains($api_key, 'Bearer')) {
$api_key = explode(' ', $api_key)[1];
}
return $api_key;
}
public function generate(int $length = 32, bool $removeSimilarCharacters = true): string {
$token = "";
try {
$bytesWithMargin = random_bytes($length*3);
$base64 = base64_encode($bytesWithMargin);
$purified = preg_replace("/[+=\/.]/", "", $base64);
if ($removeSimilarCharacters) {
$purified = preg_replace("/[I1l0Oo]/", "", $purified);
}
$token = substr($purified, 0, $length);
} catch (\Exception $e){
error_log(var_export($e, true));
}
return $token;
}
public function generateToken(): object {
$selector = bin2hex(\random_bytes(12));
$token = bin2hex(\random_bytes(20));
$full = "{$selector}:{$token}";
$token = password_hash($token, \PASSWORD_DEFAULT);
return (object) compact('selector', 'token', 'full');
}
}

28
composer.json Normal file
View File

@ -0,0 +1,28 @@
{
"name": "incoviba/api",
"type": "project",
"require": {
"slim/slim": "^4.9",
"php-di/slim-bridge": "^3.2",
"zeuxisoo/slim-whoops": "^0.7.3",
"slim/psr7": "^1.5",
"nesbot/carbon": "^2.54",
"j4mie/paris": "^1.5"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
"kint-php/kint": "^3.3"
},
"autoload": {
"psr-4": {
"Incoviba\\": "src/",
"Incoviba\\API\\Common\\": "common/"
}
},
"authors": [
{
"name": "Aldarien",
"email": "aldarien85@gmail.com"
}
]
}

66
docker-compose.yml Normal file
View File

@ -0,0 +1,66 @@
version: '3'
x-restart:
&restart
restart: unless-stopped
x-timezone:
&tz
TZ: America/Santiago
services:
proxy:
image: nginx:alpine
container_name: incoviba_proxy
<<: *restart
environment: *tz
ports:
- "8081:80"
volumes:
- ./:/code
- ./nginx.conf:/etc/nginx/conf.d/default.conf
networks:
- incoviba
api:
build:
dockerfile: Dockerfile
container_name: incoviba_api
<<: *restart
environment: *tz
env_file:
- .env
- .db.env
- .api.key
volumes:
- ./:/code
- ./php.ini:/usr/local/etc/php/conf.d/docker.ini
- ./logs/php/:/var/log/php/
networks:
- incoviba
db:
container_name: db
image: mariadb:latest
<<: *restart
environment: *tz
env_file: .db.env
volumes:
- incoviba_data:/var/lib/mysql
networks:
- incoviba
adminer:
container_name: adminer
image: adminer:latest
<<: *restart
environment: *tz
ports:
- "8083:8080"
env_file: .adminer.env
networks:
- incoviba
volumes:
incoviba_data: {}
networks:
incoviba:
external: true

36
nginx.conf Normal file
View File

@ -0,0 +1,36 @@
server {
listen 80;
server_name api;
index index.php;
error_log /code/logs/error.log;
access_log /code/logs/access.log;
root /code/public;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
add_header 'Content-Type' 'application/json';
add_header 'Content-Length' 0;
return 204;
}
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_index index.php;
fastcgi_pass api:9000;
}
}

1945
php.ini Normal file

File diff suppressed because it is too large Load Diff

BIN
php.prod.ini Normal file

Binary file not shown.

7
public/index.php Normal file
View File

@ -0,0 +1,7 @@
<?php
include_once implode(DIRECTORY_SEPARATOR, [
dirname(__FILE__, 2),
'setup',
'app.php'
]);
$app->run();

View File

@ -0,0 +1,8 @@
<?php
use Incoviba\API\Common\Controller\Auth;
$app->post('/auth/login[/]', [Auth::class, 'login']);
$app->get('/auth/generate[/]', [Auth::class, 'generate']);
$app->post('/auth/validate[/]', [Auth::class, 'validate']);
$app->post('/auth/user[/]', [Auth::class, 'user']);
$app->post('/auth/logout[/]', [Auth::class, 'logout']);

View File

@ -0,0 +1,12 @@
<?php
use Incoviba\API\Common\Controller\Bancos;
$app->group('/bancos', function ($app) {
$app->post('/add[/]', [Bancos::class, 'add']);
$app->get('[/]', Bancos::class);
});
$app->group('/banco/{banco_id}', function ($app) {
$app->put('/edit[/]', [Bancos::class, 'edit']);
$app->delete('/delete[/]', [Bancos::class, 'delete']);
$app->get('[/]', [Bancos::class, 'show']);
});

View File

@ -0,0 +1,5 @@
<?php
use Incoviba\API\Common\Controller\Base;
$app->get('[/]', Base::class);
$app->get('/php/info[/]', [Base::class, 'info']);

View File

@ -0,0 +1,5 @@
<?php
use Incoviba\API\Common\Controller\Configs;
$app->get('/config/{config_name}', [Configs::class, 'get']);
$app->post('/config', [Configs::class, 'set']);

View File

@ -0,0 +1,13 @@
<?php
use Incoviba\API\Common\Controller\Inmobiliarias;
$app->group('/inmobiliarias', function ($app) {
$app->post('/add[/]', [Inmobiliarias::class, 'add']);
$app->get('[/]', Inmobiliarias::class);
});
$app->group('/inmobiliaria/{inmobiliaria_rut}', function ($app) {
$app->get('/proyectos[/]', [Inmobiliarias::class, 'proyectos']);
$app->put('/edit[/]', [Inmobiliarias::class, 'edit']);
$app->delete('/delete[/]', [Inmobiliarias::class, 'delete']);
$app->get('[/]', [Inmobiliarias::class, 'show']);
});

View File

@ -0,0 +1,12 @@
<?php
use Incoviba\API\Common\Controller\Propietarios;
$app->group('/propietarios', function ($app) {
$app->post('/add[/]', [Propietarios::class, 'add']);
$app->get('[/]', Propietarios::class);
});
$app->group('/propietario/{propietario_rut}', function ($app) {
$app->put('/edit[/]', [Propietarios::class, 'edit']);
$app->delete('/edit[/]', [Propietarios::class, 'delete']);
$app->get('[/]', [Propietarios::class, 'show']);
});

View File

@ -0,0 +1,22 @@
<?php
use Incoviba\API\Common\Controller\Proyectos;
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->group('/proyecto/{proyecto_id}', function ($app) {
$app->put('/edit[/]', [Proyectos::class, 'edit']);
$app->delete('/edit[/]', [Proyectos::class, 'delete']);
$app->get('[/]', [Proyectos::class, 'show']);
});

View File

@ -0,0 +1,16 @@
<?php
$folder = implode(DIRECTORY_SEPARATOR, [
__DIR__,
'tipos'
]);
if (file_exists($folder)) {
$app->group('/tipos', function ($app) use ($folder) {
$files = new DirectoryIterator($folder);
foreach ($files as $file) {
if ($file->isDir() or $file->getExtension() !== 'php') {
continue;
}
include_once $file->getRealPath();
}
});
}

View File

@ -0,0 +1,12 @@
<?php
use Incoviba\API\Common\Controller\Sociedades;
$app->group('/sociedades', function ($app) {
$app->post('/add[/]', [Sociedades::class, 'add']);
$app->get('[/]', Sociedades::class);
});
$app->group('/sociedad/{sociedad_id}', function ($app) {
$app->put('/edit[/]', [Sociedades::class, 'edit']);
$app->delete('/edit[/]', [Sociedades::class, 'delete']);
$app->get('[/]', [Sociedades::class, 'show']);
});

View File

@ -0,0 +1,12 @@
<?php
use Incoviba\API\Common\Controller\Ventas;
$app->group('/ventas', function ($app) {
$app->post('/add[/]', [Ventas::class, 'add']);
$app->get('[/]', Ventas::class);
});
$app->group('/venta/{venta_id}', function ($app) {
$app->put('/edit[/]', [Ventas::class, 'edit']);
$app->delete('/edit[/]', [Ventas::class, 'delete']);
$app->get('[/]', [Ventas::class, 'show']);
});

53
setup/app.php Normal file
View File

@ -0,0 +1,53 @@
<?php
use DI\ContainerBuilder as Builder;
use DI\Bridge\Slim\Bridge;
include_once 'composer.php';
$builder = new Builder();
$folders = [
'settings',
'setups'
];
foreach ($folders as $f) {
$folder = implode(DIRECTORY_SEPARATOR, [
__DIR__,
$f
]);
if (!file_exists($folder)) {
continue;
}
$files = new DirectoryIterator($folder);
foreach ($files as $file) {
if ($file->isDir()) {
continue;
}
$builder->addDefinitions($file->getRealPath());
}
}
$container = $builder->build();
$app = Bridge::create($container);
if ($app->getContainer()->has('base_url')) {
$app->setBasePath($app->getContainer()->get('base_url'));
}
$folder = implode(DIRECTORY_SEPARATOR, [
__DIR__,
'middlewares'
]);
if (file_exists($folder)) {
$files = new DirectoryIterator($folder);
foreach ($files as $file) {
if ($file->isDir() and $file->getExtension() != 'php') {
continue;
}
include_once $file->getRealPath();
}
}
$app->addRoutingMiddleware();
include_once 'databases.php';
include_once 'router.php';

6
setup/composer.php Normal file
View File

@ -0,0 +1,6 @@
<?php
include_once implode(DIRECTORY_SEPARATOR, [
dirname(__FILE__, 2),
'vendor',
'autoload.php'
]);

24
setup/databases.php Normal file
View File

@ -0,0 +1,24 @@
<?php
$database = $app->getContainer()->get('database');
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([
'connection_string' => $dsn,
'username' => $settings->user->name,
'password' => $settings->user->password
], null, $name);
break;
}
if (isset($settings->logging) and $settings->logging) {
ORM::configure('logging', true, $name);
}
if (isset($settings->caching) and $settings->caching) {
ORM::configure('caching', true, $name);
}
}
if (isset($database->short_names) and $database->short_names) {
Model::$short_table_names = true;
}

View File

@ -0,0 +1,4 @@
<?php
use Psr\Container\ContainerInterface as Container;
$app->add($app->getContainer()->get(Zeuxisoo\Whoops\Slim\WhoopsMiddleware::class));

View File

@ -0,0 +1,2 @@
<?php
$app->add($app->getContainer()->get(Incoviba\API\Common\Middleware\Auth::class));

9
setup/router.php Normal file
View File

@ -0,0 +1,9 @@
<?php
$folder = $app->getContainer()->get('folders')->routes;
$files = new DirectoryIterator($folder);
foreach ($files as $file) {
if ($file->isDir() or $file->getExtension() != 'php') {
continue;
}
include_once $file->getRealPath();
}

View File

@ -0,0 +1,5 @@
<?php
return [
'debug' => $_ENV['DEBUG'] ?? false,
'API_KEY' => $_ENV['API_KEY']
];

View File

@ -0,0 +1,24 @@
<?php
return [
'database' => function() {
$arr = [
'default' => (object) [
'engine' => 'mysql',
'host' => (object) [
'name' => $_ENV['MYSQL_HOST'] ?? 'db'
],
'user' => (object) [
'name' => $_ENV['MYSQL_USER'],
'password' => $_ENV['MYSQL_PASSWORD']
],
'name' => $_ENV['MYSQL_DATABASE'],
'logging' => true,
'caching' => true
]
];
return (object) [
'short_names' => true,
'databases' => $arr
];
}
];

View File

@ -0,0 +1,15 @@
<?php
return [
'folders' => function() {
$arr = ['base' => dirname(__FILE__, 3)];
$arr['resources'] = implode(DIRECTORY_SEPARATOR, [
$arr['base'],
'resources'
]);
$arr['routes'] = implode(DIRECTORY_SEPARATOR, [
$arr['resources'],
'routes'
]);
return (object) $arr;
}
];

11
setup/setups/01_env.php Normal file
View File

@ -0,0 +1,11 @@
<?php
use Psr\Container\ContainerInterface as Container;
return [
Zeuxisoo\Whoops\Slim\WhoopsMiddleware::class => function(Container $c) {
return new Zeuxisoo\Whoops\Slim\WhoopsMiddleware([
'enable' => $c->get('debug'),
'editor' => 'vscode'
]);
}
];

15
setup/setups/02_auth.php Normal file
View File

@ -0,0 +1,15 @@
<?php
use Psr\Container\ContainerInterface as Container;
return [
Incoviba\API\Common\Service\Auth::class => function(Container $c) {
return new Incoviba\API\Common\Service\Auth($c->get('API_KEY'));
},
Incoviba\API\Common\Middleware\Auth::class => function(Container $c) {
return new Incoviba\API\Common\Middleware\Auth(
$c->get(Incoviba\API\Common\Service\Auth::class),
$c->get(Slim\Psr7\Factory\ResponseFactory::class),
['/auth/generate']
);
}
];

14
src/Admin/Config.php Normal file
View File

@ -0,0 +1,14 @@
<?php
namespace Incoviba\Admin;
use Incoviba\API\Common\Alias\Model;
/**
* @property int $id
* @property string $name
* @property string $value
*/
class Config extends Model {
public static $_table = 'configurations';
protected static $fields = ['name', 'value'];
}

48
src/Auth/Login.php Normal file
View File

@ -0,0 +1,48 @@
<?php
namespace Incoviba\Auth;
use Carbon\Carbon;
use DateTime;
use Incoviba\API\Common\Alias\Model;
use Incoviba\Admin\Config;
/**
* @property int $id
* @property int $user_id
* @property DateTime $time
* @property string $selector
* @property string $token
* @property int $status
*
*/
class Login extends Model {
public static $_table = 'logins';
protected static $fields = ['user_id', 'time', 'selector', 'token', 'status'];
protected $user;
public function user() {
if ($this->user === null) {
$this->user = $this->childOf(User::class, [Model::SELF_KEY => 'user_id']);
}
return $this->user;
}
public function time(DateTime $time = null) {
if ($time === null) {
return Carbon::parse($this->time);
}
$this->time = $time->format('Y-m-d H:m:s');
return null;
}
public function isValid() {
if ($this->status == 0) {
return false;
}
$expiration = $this->factory->find(Config::class)->where([['name', 'cookie_expiration_time']])->one();
if ($this->time()->diffInSeconds() > $expiration->value) {
$this->status = 0;
$this->save();
return false;
}
return true;
}
}

79
src/Auth/User.php Normal file
View File

@ -0,0 +1,79 @@
<?php
namespace Incoviba\Auth;
use Carbon\Carbon;
use Incoviba\Admin\Config;
use Incoviba\API\Common\Alias\Model;
/**
* @property int $id
* @property string $name
* @property string $password
* @property int $enabled
*/
class User extends Model {
public static $_table = 'users';
protected $logins;
public function logins() {
if ($this->logins === null) {
$this->logins = $this->parentOf(Login::class, [Model::CHILD_KEY => 'user_id']);
}
return $this->logins;
}
protected $login;
public function login() {
if ($this->login === null) {
$this->login = $this->factory->find(Login::class)
->where([['user_id', $this->id]])
->order([['column' => 'time', 'direction' => 'desc']])
->one(1);
}
return $this->login;
}
public function isIn(): bool {
return $this->login()->isValid();
}
public function validate($password): bool {
return password_verify($password, $this->password);
}
public function validLogins(): bool|array {
return $this->factory->find(Login::class)->where([['user_id', $this->id], ['status', 1]])->many();
}
public function logout() {
$logins = $this->validLogins();
if ($logins === false) {
return true;
}
$bool = true;
foreach ($logins as $login) {
$login->status = 0;
$bool &= $login->save();
}
return $bool;
}
public function setToken($selector, $token) {
$this->logout();
$expiration = $this->factory->find(Config::class)->where([['name', 'cookie_expiration_time']])->one();
$data = [
'user_id' => $this->id,
'time' => Carbon::now()->format('Y-m-d H:i:s '),
'selector' => $selector,
'token' => $token,
'status' => 1
];
$output = [
'input' => $data,
'login' => null,
'logged_in' => false
];
$login = Login::add($this->factory, $data);
$output['login'] = $login;
if ($login !== false and $login->is_new()) {
$output['logged_in'] = $login->save();
$output['expires'] = $login->time()->addSeconds($expiration->value)->timestamp;
}
return $output;
}
}

13
src/Common/Banco.php Normal file
View File

@ -0,0 +1,13 @@
<?php
namespace Incoviba\Common;
use Incoviba\API\Common\Alias\Model;
/**
* @property int $id
* @property string $nombre
*/
class Banco extends Model {
public static $_table = 'banco';
protected static $fields = ['nombre'];
}

14
src/Common/Comuna.php Normal file
View File

@ -0,0 +1,14 @@
<?php
namespace Incoviba\Common;
use Incoviba\API\Common\Alias\Model;
/**
* @property int $id
* @property string $descripcion
* @property Provincia $provincia
*/
class Comuna extends Model {
public static $_table = 'comuna';
protected static $fields = ['descripcion', 'provincia'];
}

24
src/Common/Direccion.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace Incoviba\Common;
use Incoviba\API\Common\Alias\Model;
/**
* @property int $id
* @property string $calle
* @property int $numero
* @property string $extra
* @property Comuna $comuna
*/
class Direccion extends Model {
public static $_table = 'direccion';
protected static $fields = ['calle', 'numero', 'extra', 'comuna'];
protected ?Comuna $comuna_o;
public function comuna(): ?Comuna {
if ($this->comuna_o === null) {
$this->comuna_o = $this->childOf(Comuna::class, [Model::SELF_KEY => 'comuna']);
}
return $this->comuna_o;
}
}

29
src/Common/Provincia.php Normal file
View File

@ -0,0 +1,29 @@
<?php
namespace Incoviba\Common;
use Incoviba\API\Common\Alias\Model;
/**
* @property int $id
* @property string $descripcion
* @property Region $region
*/
class Provincia extends Model {
public static $_table = 'provincia';
protected static $fields = ['descripcion', 'region'];
protected ?Region $region_o;
public function region(): ?Region {
if ($this->region_o === null) {
$this->region_o = $this->childOf(Region::class, [Model::SELF_KEY => 'region']);
}
return $this->region_o;
}
protected ?array $comunas;
public function comunas(): ?array {
if ($this->comunas === null) {
$this->comunas = $this->parentOf(Comuna::class, [Model::CHILD_KEY => 'provincia']);
}
return $this->comunas;
}
}

23
src/Common/Region.php Normal file
View File

@ -0,0 +1,23 @@
<?php
namespace Incoviba\Common;
use Incoviba\API\Common\Alias\Model;
/**
* @property int $id
* @property string $descripcion
* @property string $numeral
* @property int $numeracion
*/
class Region extends Model {
public static $_table = 'region';
protected static $fields = ['descripcion', 'numeral', 'numeracion'];
protected ?array $provincias;
public function provincias(): ?array {
if ($this->provincias === null) {
$this->provincias = $this->parentOf(Provincia::class, [Model::CHILD_KEY => 'region']);
}
return $this->provincias;
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace Incoviba\Inmobiliaria;
use Incoviba\API\Common\Alias\Model;
use Incoviba\Common\Banco;
use Incoviba\Proyecto\Proyecto;
/**
* @property int $rut
* @property string $dv
* @property string $razon
* @property string $abreviacion
* @property string $cuenta
* @property Banco $banco
* @property TipoSociedad $sociedad
*/
class Inmobiliaria extends Model {
public static $_table = 'inmobiliaria';
public static $_id_column = ['rut'];
protected static $fields = ['rut', 'dv', 'razon', 'abreviacion', 'cuenta'];
protected $banco_o;
public function banco() {
if ($this->banco_o === null) {
$this->banco_o = $this->childOf(Banco::class, [Model::SELF_KEY => 'banco']);
}
return $this->banco_o;
}
protected $sociedad_o;
public function sociedad() {
if ($this->sociedad_o === null) {
$this->sociedad_o = $this->childOf(TipoSociedad::class, [Model::SELF_KEY => 'sociedad']);
}
return $this->sociedad_o;
}
protected $proyectos;
public function proyectos(): ?array {
if ($this->proyectos === null) {
$this->proyectos = $this->parentOf(Proyecto::class, [Model::CHILD_KEY => 'inmobiliaria', Model::SELF_KEY => 'rut']);
}
return $this->proyectos;
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace Incoviba\Inmobiliaria;
use Incoviba\API\Common\Alias\Model;
class TipoSociedad extends Model {
public static $_table = 'tipo_sociedad';
protected static $fields = ['descripcion', 'abreviacion'];
}

179
src/Proyecto/Proyecto.php Normal file
View File

@ -0,0 +1,179 @@
<?php
namespace Incoviba\Proyecto;
use Carbon\Carbon;
use Incoviba\API\Common\Alias\Model;
use Incoviba\Common\Direccion;
use Incoviba\Inmobiliaria\Inmobiliaria;
use Incoviba\Venta\Cuota;
use Incoviba\Venta\Cierre;
/**
* @property int $id
* @property Inmobiliaria $inmobiliaria
* @property string $descripcion
* @property Direccion $direccion
* @property double $superficie_terreno
* @property double $valor_terreno;
* @property double $corredor;
* @property double $superficie_sobre_terreno;
* @property double $superficie_bajo_terreno;
* @property int $pisos;
* @property int $subterraneos;
*/
class Proyecto extends Model {
public static $_table = 'proyecto';
protected static $fields = ['inmobiliaria', 'descripcion', 'direccion', 'superficie_terreno', 'valor_terreno',
'corredor', 'superficie_sobre_terreno', 'superficie_bajo_terreno', 'pisos', 'subterraneos'];
protected $direccion_o;
public function direccion() {
if ($this->direccion_o === null) {
$this->direccion_o = $this->childOf(Direccion::class, [Model::SELF_KEY => 'direccion']);
}
return $this->direccion_o;
}
protected $inmobiliaria_o;
public function inmobiliaria() {
if ($this->inmobiliaria_o === null) {
$this->inmobiliaria_o = $this->childOf(Inmobiliaria::class, [Model::SELF_KEY => 'inmobiliaria', Model::PARENT_KEY => 'rut']);
}
return $this->inmobiliaria_o;
}
protected $cuotas;
protected function buildCuotas() {
return $this->factory->find(Cuota::class)
->join([
['venta', 'venta.pie', 'cuota.pie'],
['JOIN (SELECT e1.* FROM estado_venta e1 JOIN (SELECT MAX(id) AS id, venta FROM estado_venta GROUP BY venta) e0 ON e0.id = e1.id)', 'ev.venta', 'venta.id', 'alias' => 'ev', 'type' => 'raw'],
['tipo_estado_venta', 'tev.id', 'ev.estado', 'alias' => 'tev'],
['propiedad', 'propiedad.id', 'venta.propiedad'],
['propiedad_unidad', 'pu.propiedad', 'propiedad.id', 'alias' => 'pu'],
['unidad', 'unidad.id', 'pu.unidad'],
['proyecto_tipo_unidad', 'ptu.id', 'unidad.pt', 'alias' => 'ptu'],
['proyecto', 'proyecto.id', 'ptu.proyecto'],
['pago', 'pago.id', 'cuota.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.pago', 'pago.id', 'alias' => 'ep', 'type' => 'raw'],
['tipo_estado_pago', 'tep.id', 'ep.estado', 'alias' => 'tep']
])
->where([
['proyecto.id', $this->id],
['tev.activa', 1],
['tep.active', 1]
]);
}
public function cuotas() {
if ($this->cuotas === null or !isset($this->cuotas->total)) {
$cuotas = [];
if ($this->cuotas !== null) {
$cuotas = (array) $this->cuotas;
}
$cuotas['total'] = $this->$this->buildCuotas()->many();
$this->cuotas = (object) $cuotas;
}
return $this->cuotas->total;
}
public function cuotasHoy() {
if ($this->cuotas === null or !isset($this->cuotas->hoy)) {
$cuotas = [];
if ($this->cuotas !== null) {
$cuotas = (array) $this->cuotas;
}
$f = Carbon::today();
$cuotas['hoy'] = $this->buildCuotas()
->where([
['pago.fecha', $f->format('Y-m-d')]
])
->many();
$this->cuotas = (object) $cuotas;
}
return $this->cuotas->hoy;
}
public function cuotasPendientes() {
if (!isset($this->cuotas) or !isset($this->cuotas->mes)) {
$cuotas = [];
if (isset($this->cuotas)) {
$cuotas = (array) $this->cuotas;
}
$f = Carbon::today();
$cuotas['pendientes'] = $this->buildCuotas()
->where([
['ep.estado', 1, '<'],
['ep.estado', 0, '>=']
])
->many();
$this->cuotas = (object) $cuotas;
}
return $this->cuotas->pendientes;
}
public function cuotasMes() {
if (!isset($this->cuotas) or !isset($this->cuotas->mes)) {
$cuotas = [];
if (isset($this->cuotas)) {
$cuotas = (array) $this->cuotas;
}
$f = Carbon::today();
error_log(var_export($this->buildCuotas(), true));
$cuotas['mes'] = $this->buildCuotas()
->where([
['pago.fecha', $f->format('Y-m-d'), 'operator' => '>'],
['pago.fecha', $f->copy()->addMonth(1)->format('Y-m-d'), '<=']
])
->many();
$this->cuotas = (object) $cuotas;
}
return $this->cuotas->mes;
}
protected $cierres;
public function cierres(int $vigentes = 0)
{
if (!isset($this->cierres[$vigentes]) or $this->cierres[$vigentes] == null) {
$orm = $this->factory->find(Cierre::class)
->select([['cierre', '*']])
->join([
['join (select e1.* from estado_cierre e1 join (select cierre, max(id) as id from estado_cierre group by cierre) e0 on e0.id = e1.id)',
'ec.cierre', 'cierre.id', 'alias' => 'ec', 'type' => 'raw'],
['tipo_estado_cierre', 'tipo_estado_cierre.id', 'ec.tipo'],
['proyecto', 'proyecto.id', 'cierre.proyecto'],
['unidad_cierre', 'unidad_cierre.cierre', 'cierre.id'],
['unidad', 'unidad.id', 'unidad_cierre.unidad']
])
->where([
['proyecto.id', $this->id],
['unidad_cierre.principal', 1]
])
->order([
'proyecto.descripcion',
'tipo_estado_cierre.vigente',
'cierre.fecha',
'LPAD(unidad.descripcion, 4, "0")'
])
->group(['cierre.id']);
switch ($vigentes) {
case Cierre::VIGENTES:
$orm = $orm->where([['tipo_estado_cierre.vigente', 1]]);
break;
case Cierre::NO_VIGENTES:
$orm = $orm->where([['tipo_estado_cierre.vigente', 0]]);
break;
case (Cierre::VIGENTES + 1):
$orm = $orm->where([
['tipo_estado_cierre.vigente', 1],
['tipo_estado_cierre.descripcion', 'promesado', 'type' => 'not like']
]);
break;
case (Cierre::VIGENTES + 2):
$orm = $orm->where([
['tipo_estado_cierre.vigente', 1],
['tipo_estado_cierre.descripcion', 'promesado', 'type' => 'like']
]);
break;
};
error_log(var_export($orm, true));
$this->cierres[$vigentes] = $orm->many();
}
return $this->cierres[$vigentes];
}
}

29
src/Venta/Agente.php Normal file
View File

@ -0,0 +1,29 @@
<?php
namespace Incoviba\Venta;
use Incoviba\API\Common\Alias\Model;
use Incoviba\Common\Direccion;
/**
* @property int $id
* @property TipoAgente $tipo
* @property int $rut
* @property string $descripcion
* @property string $representante
* @property int $telefono
* @property string $correo
* @property Direccion $direccion
* @property string $giro
* @property string $abreviacion
*/
class Agente extends Model {
public static $_table = 'agente';
protected $ats;
public function agenteTipos() {
if ($this->ats === null) {
$this->ats = $this->parentOf(AgenteTipo::class, [Model::CHILD_KEY => 'agente']);
}
return $this->ats;
}
}

31
src/Venta/AgenteTipo.php Normal file
View File

@ -0,0 +1,31 @@
<?php
namespace Incoviba\Venta;
use Incoviba\API\Common\Alias\Model;
class AgenteTipo extends Model {
public static $_table = 'agente_tipo';
protected $agente_o;
public function agente() {
if ($this->agente_o === null) {
$this->agente_o = $this->childOf(Agente::class, [Model::SELF_KEY => 'agente']);
}
return $this->agente_o;
}
protected $tipo_o;
public function tipo() {
if ($this->tipo_o === null) {
$this->tipo_o = $this->childOf(TipoAgente::class, [Model::SELF_KEY => 'tipo']);
}
return $this->tipo_o;
}
protected $pas;
public function proyectoAgentes() {
if ($this->pas === null) {
$this->pas = $this->parentOf(ProyectoAgente::class, [Model::CHILD_KEY => 'agente']);
}
return $this->pas;
}
}

6
src/Venta/BonoPie.php Normal file
View File

@ -0,0 +1,6 @@
<?php
namespace Incoviba\Venta;
use Incoviba\API\Common\Alias\Model;
class BonoPie extends Model {}

25
src/Venta/Cierre.php Normal file
View File

@ -0,0 +1,25 @@
<?php
namespace Incoviba\Venta;
use Carbon\Carbon;
use Incoviba\API\Common\Alias\Model;
class Cierre extends Model {
public static $_table = 'cierre';
const VIGENTES = 1;
const NO_VIGENTES = -1;
public function fecha(\DateTimeInterface $fecha = null)
{
if ($fecha == null) {
return Carbon::parse($this->fecha);
}
$this->fecha = $fecha->format('Y-m-d');
}
public function periodo() {
$today = Carbon::today();
$dif = $today->diffInDays($this->fecha());
return $dif;
}
}

6
src/Venta/Credito.php Normal file
View File

@ -0,0 +1,6 @@
<?php
namespace Incoviba\Venta;
use Incoviba\API\Common\Alias\Model;
class Credito extends Model {}

33
src/Venta/Cuota.php Normal file
View File

@ -0,0 +1,33 @@
<?php
namespace Incoviba\Venta;
use DateTimeInterface;
use Incoviba\API\Common\Alias\Model;
use Incoviba\Common\Banco;
/**
* @property int $id
* @property Pie $pie
* @property DateTimeInterface $fecha
* @property float $valor_$
* @property bool $estado
* @property Banco $banco
* @property DateTimeInterface $fecha_pago
* @property bool $abonado
* @property DateTimeInterface $fecha_abono
* @property float $uf
* @property Pago $pago
* @property int $numero
*/
class Cuota extends Model {
public static $_table = 'cuota';
protected static $fields = ['pie', 'fecha', 'valor_$', 'estado', 'banco', 'fecha_pago', 'abonado', 'fecha_abono', 'uf', 'pago', 'numero'];
protected $pago_o;
public function pago() {
if ($this->pago_o === null) {
$this->pago_o = $this->childOf(Pago::class, [Model::SELF_KEY => 'pago']);
}
return $this->pago_o;
}
}

6
src/Venta/Entrega.php Normal file
View File

@ -0,0 +1,6 @@
<?php
namespace Incoviba\Venta;
use Incoviba\API\Common\Alias\Model;
class Entrega extends Model {}

6
src/Venta/Escritura.php Normal file
View File

@ -0,0 +1,6 @@
<?php
namespace Incoviba\Venta;
use Incoviba\API\Common\Alias\Model;
class Escritura extends Model {}

View File

@ -0,0 +1,6 @@
<?php
namespace Incoviba\Venta;
use Incoviba\API\Common\Alias\Model;
class EstadoVenta extends Model {}

38
src/Venta/Pago.php Normal file
View File

@ -0,0 +1,38 @@
<?php
namespace Incoviba\Venta;
use Carbon\Carbon;
use DateTimeInterface;
use Incoviba\API\Common\Alias\Model;
use Incoviba\Common\Banco;
/**
* @property int $id
* @property float $valor
* @property Banco $banco
* @property TipoPago $tipo
* @property string $identificador
* @property DateTimeInterface $fecha
* @property float $uf
* @property string $pagador
* @property Pago $asociado
*/
class Pago extends Model {
public static $_table = 'pago';
protected static $fields = ['valor', 'banco', 'tipo', 'identificador', 'fecha', 'uf', 'pagador', 'asociado'];
protected $tipo_o;
public function tipo() {
if ($this->tipo_o === null) {
$this->tipo_o = $this->childOf(TipoPago::class, [Model::SELF_KEY => 'tipo']);
}
return $this->tipo_o;
}
public function fecha(DateTimeInterface $fecha = null) {
if ($fecha === null) {
return Carbon::parse($this->fecha);
}
$this->fecha = $fecha->format('Y-m-d');
}
}

6
src/Venta/Pie.php Normal file
View File

@ -0,0 +1,6 @@
<?php
namespace Incoviba\Venta;
use Incoviba\API\Common\Alias\Model;
class Pie extends Model {}

6
src/Venta/Promocion.php Normal file
View File

@ -0,0 +1,6 @@
<?php
namespace Incoviba\Venta;
use Incoviba\API\Common\Alias\Model;
class Promocion extends Model {}

6
src/Venta/Propiedad.php Normal file
View File

@ -0,0 +1,6 @@
<?php
namespace Incoviba\Venta;
use Incoviba\API\Common\Alias\Model;
class Propiedad extends Model {}

31
src/Venta/Propietario.php Normal file
View File

@ -0,0 +1,31 @@
<?php
namespace Incoviba\Venta;
use Incoviba\API\Common\Alias\Model;
use Incoviba\Common\Direccion;
class Propietario extends Model {
public static $_table = 'propietario';
public static $_id_column = ['rut'];
protected $direccion_o;
public function direccion() {
if ($this->direccion_o === null) {
$this->direccion_o = $this->childOf(Direccion::class, [Model::SELF_KEY => 'direccion']);
}
return $this->direccion_o;
}
public function nombreCompleto() {
return implode(' ', [
$this->nombres,
$this->apellidos()
]);
}
public function apellidos() {
return implode(' ', [
$this->apellido_paterno,
$this->apellido_materno
]);
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace Incoviba\Venta;
use Incoviba\API\Common\Alias\Model;
use Incoviba\Proyecto\Proyecto;
class ProyectoAgente extends Model {
public static $_table = 'proyecto_agente';
protected $at;
public function agenteTipo() {
if ($this->at === null) {
$this->at = $this->childOf(AgenteTipo::class, [Model::SELF_KEY => 'agente']);
}
return $this->at;
}
protected $proyecto_o;
public function proyecto() {
if ($this->proyecto_o === null) {
$this->proyecto_o = $this->childOf(Proyecto::class, [Model::SELF_KEY => 'proyecto']);
}
return $this->proyecto_o;
}
}

View File

@ -0,0 +1,6 @@
<?php
namespace Incoviba\Venta;
use Incoviba\API\Common\Alias\Model;
class Resciliacion extends Model {}

6
src/Venta/Subsidio.php Normal file
View File

@ -0,0 +1,6 @@
<?php
namespace Incoviba\Venta;
use Incoviba\API\Common\Alias\Model;
class Subsidio extends Model {}

16
src/Venta/TipoAgente.php Normal file
View File

@ -0,0 +1,16 @@
<?php
namespace Incoviba\Venta;
use Incoviba\API\Common\Alias\Model;
class TipoAgente extends Model {
public static $_table = 'tipo_agente';
protected $ats;
public function agentesTipos() {
if ($this->ats === null) {
$this->ats = $this->parentOf(AgenteTipo::class, [Model::CHILD_KEY => 'tipo']);
}
return $this->ats;
}
}

12
src/Venta/TipoPago.php Normal file
View File

@ -0,0 +1,12 @@
<?php
namespace Incoviba\Venta;
use Incoviba\API\Common\Alias\Model;
/**
* @property int $id
* @property string $descripcion
*/
class TipoPago extends Model {
public static $_table = 'tipo_pago';
}

144
src/Venta/Venta.php Normal file
View File

@ -0,0 +1,144 @@
<?php
namespace Incoviba\Venta;
use DateTime;
use Incoviba\API\Common\Alias\Model;
/**
* @property int $id
* @property Propietario $propietario
* @property Propiedad $propiedad
* @property ?Pie $pie
* @property ?BonoPie $bono_pie
* @property ?Credito $credito
* @property ?Escritura $escritura
* @property ?Subsidio $subsidio
* @property ?DateTime $escriturado
* @property ?Entrega $entrega
* @property ?DateTime $entregado
* @property DateTime $fecha
* @property double $valor_uf
* @property int $estado
* @property ?DateTime $fecha_entrega
* @property int $avalchile
* @property Agente $agente
* @property double $uf
* @property int $relacionado
* @property ?Promocion $promocion
* @property ?Resciliacion $resciliacion
* @property ?Pago $devolucion
*/
class Venta extends Model {
public static $_table = 'venta';
protected static $field = ['propietario', 'propiedad', 'pie', 'bono_pie', 'credito', 'escritura', 'subsidio',
'escriturado', 'entrega', 'entregado', 'fecha', 'valor_uf', 'estado', 'fecha_entrega', 'avalchile', 'agente', 'uf',
'relacionado', 'promocion', 'resciliacion', 'devolucion'];
protected $propietario_o;
public function propietario() {
if ($this->propietario_o === null) {
$this->propietario_o = $this->childOf(Propietario::class, [Model::SELF_KEY => 'propietario', Model::PARENT_KEY => 'rut']);
}
return $this->propietario_o;
}
protected $propiedad_o;
public function propiedad() {
if ($this->propiedad_o === null) {
$this->propiedad_o = $this->childOf(Propiedad::class, [Model::SELF_KEY => 'propiedad']);
}
return $this->propiedad_o;
}
protected $pie_o;
public function pie() {
if($this->pie_o === null) {
$this->pie_o = $this->childOf(Pie::class, [Model::SELF_KEY => 'pie']);
}
return $this->pie_o;
}
protected $bono;
public function bono() {
if ($this->bono === null) {
$this->bono = $this->childOf(BonoPie::class, [Model::SELF_KEY => 'bono_pie']);
}
return $this->bono;
}
protected $credito_o;
public function credito() {
if ($this->credito_o === null) {
$this->credito_o = $this->childOf(Credito::class, [Model::SELF_KEY => 'credito']);
}
return $this->credito_o;
}
protected $escritura_o;
public function escritura() {
if ($this->escritura_o === null) {
$this->escritura_o = $this->childOf(Escritura::class, [Model::SELF_KEY => 'escritura']);
}
return $this->escritura_o;
}
protected $subsidio_o;
public function subsidio() {
if ($this->subsidio_o === null) {
$this->subsidio_o = $this->childOf(Subsidio::class, [Model::SELF_KEY => 'subsidio']);
}
return $this->subsidio_o;
}
protected $entrega_o;
public function entrega() {
if ($this->entrega_o === null) {
$this->entrega_o = $this->childOf(Entrega::class, [Model::SELF_KEY => 'entrega']);
}
return $this->entrega_o;
}
protected $pa;
public function proyectoAgente() {
if ($this->pa === null) {
$this->pa = $this->childOf(ProyectoAgente::class, [Model::SELF_KEY => 'agente']);
}
return $this->pa;
}
protected $promocion_o;
public function promocion() {
if ($this->promocion_o === null) {
$this->promocion_o = $this->childOf(Promocion::class, [Model::SELF_KEY => 'promocion']);
}
return $this->promocion_o;
}
protected $resciliacion_o;
public function resciliacion() {
if ($this->resciliacion_o === null) {
$this->resciliacion_o = $this->childOf(Resciliacion::class, [Model::SELF_KEY => 'resciliacion']);
}
return $this->resciliacion_o;
}
protected $devolucion_o;
public function devolucion() {
if ($this->devolucion_o === null) {
$this->devolucion_o = $this->childOf(Pago::class, [Model::SELF_KEY => 'devolucion']);
}
return $this->devolucion_o;
}
protected $estados;
public function estados() {
if ($this->estados === null) {
$this->estados = $this->parentOf(EstadoVenta::class, [Model::CHILD_KEY => 'venta']);
}
return $this->estados;
}
protected $estado;
public function estado() {
if ($this->estado === null) {
$estados = $this->estados();
usort($estados, function ($a, $b) {
$f = $b->fecha - $a->fecha;
if ($f == 0) {
return $b->id - $a->id;
}
return $f;
});
$this->estado = $estados[0];
}
return $this->estado;
}
}