This commit is contained in:
2021-12-25 23:17:15 -03:00
parent bbee033a8a
commit 3580738273
23 changed files with 755 additions and 81 deletions

View File

@ -90,7 +90,7 @@ abstract class Model extends BaseModel implements ModelInterface {
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): ?ModelInterface {
public static function add(ModelFactory $factory, $input): bool|ModelInterface {
$data = static::parseInput($input);
$class = get_called_class();
if (method_exists($class, 'find')) {
@ -103,7 +103,7 @@ abstract class Model extends BaseModel implements ModelInterface {
$where = array_values($where);
$obj = $factory->find($class)->where($where)->one();
}
if ($obj === null) {
if ($obj === false or $obj === null) {
$obj = $factory->create($class, $data);
}
return $obj;

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,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,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

@ -51,7 +51,7 @@ interface Model {
* @param array $input Input data
* @return Model|null
*/
public static function add(ModelFactory $factory, array $input): ?Model;
public static function add(ModelFactory $factory, array $input): bool|Model;
/**
* Edit current model parsing {$input} data

View File

@ -1,7 +1,7 @@
<?php
namespace Incoviba\API\Common\Factory;
use http\Exception\InvalidArgumentException;
use InvalidArgumentException;
use ORM;
use Incoviba\API\Common\Alias\Model as BaseModel;
use Incoviba\API\Common\Define\Model as ModelInterface;
@ -27,7 +27,7 @@ class Model {
$model = $model->where([[$f, $v]]);
}
$model = $model->one();
if ($model !== null) {
if ($model !== false and $model !== null) {
return $model;
}
}
@ -142,13 +142,20 @@ class Model {
'full', 'full outer', 'full_outer', 'fullouter', 'outer' => 'fullOuterJoin'
};
if (strtolower($join->type) == 'raw') {
if (isset($join->alias)) {
$orm = $orm->{$method}($join->table, [$join->from, $join->operator, $join->to], $join->alias, $join->params);
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 {
$orm = $orm->{$method}($join->table, [$join->from, $join->operator, $join->to], $join->params);
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]);
}
}
}
if (isset($join->alias)) {
} 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]);
@ -267,14 +274,34 @@ class Model {
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)) {
/*$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) {

View File

@ -4,48 +4,57 @@ 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 = '';
if ($request->hasHeader('Authorization')) {
$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];
}
} elseif ($request->getParsedBody() !== null and in_array('API_KEY', $request->getParsedBody())) {
$api_key = $request->getParsedBody()['API_KEY'];
} elseif ($request->getQueryParams() !== null and in_array('API_KEY', array_keys($request->getQueryParams()))) {
$api_key = $request->getQueryParams()['API_KEY'];
protected string $key;
public function __construct(string $key) {
$this->key = $key;
}
if ($this->key == $api_key) {
return true;
public function isValid(Request $request): bool {
$api_key = $this->getRequestKey($request);
if ($this->key == $api_key) {
return true;
}
return false;
}
return false;
}
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);
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;
}
$token = substr($purified, 0, $length);
} catch (\Exception $e){
echo $e->getMessage();
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');
}
return $token;
}
}

View File

@ -18,6 +18,8 @@ services:
volumes:
- ./:/code
- ./nginx.conf:/etc/nginx/conf.d/default.conf
networks:
- incoviba
api:
build:
dockerfile: Dockerfile
@ -32,6 +34,8 @@ services:
- ./:/code
- ./php.ini:/usr/local/etc/php/conf.d/docker.ini
- ./logs/php/:/var/log/php/
networks:
- incoviba
db:
container_name: db
@ -41,6 +45,8 @@ services:
env_file: .db.env
volumes:
- incoviba_data:/var/lib/mysql
networks:
- incoviba
adminer:
container_name: adminer
image: adminer:latest
@ -49,6 +55,12 @@ services:
ports:
- "8083:8080"
env_file: .adminer.env
networks:
- incoviba
volumes:
incoviba_data: {}
networks:
incoviba:
external: true

View File

@ -7,10 +7,24 @@ server {
root /code/public;
location / {
try_files $uri /index.php$is_args$args;
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;

View File

@ -1,12 +1,8 @@
<?php
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Incoviba\API\Common\Service\Auth as Service;
use Incoviba\API\Common\Controller\Auth;
$app->get('/auth/generate', function(Request $request, Response $response, Service $service): Response {
$key = $service->generate();
$response->getBody()->write(json_encode(['key' => $key]));
return $response
->withStatus(200)
->withHeader('content-type', 'application/json');
});
$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,5 @@
<?php
use Incoviba\API\Common\Controller\Configs;
$app->get('/config/{config_name}', [Configs::class, 'get']);
$app->post('/config', [Configs::class, 'set']);

View File

@ -1,8 +1,18 @@
<?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) {

View File

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

View File

@ -3,7 +3,7 @@ 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('AUTH_KEY'));
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(

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;
}
}

View File

@ -1,9 +1,12 @@
<?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
@ -19,22 +22,158 @@ use Incoviba\Inmobiliaria\Inmobiliaria;
* @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'];
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']);
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;
}
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']);
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];
}
return $this->inmobiliaria_o;
}
}

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;
}
}

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;
}
}

View File

@ -1,6 +1,38 @@
<?php
namespace Incoviba\Venta;
use Carbon\Carbon;
use DateTimeInterface;
use Incoviba\API\Common\Alias\Model;
use Incoviba\Common\Banco;
class Pago extends Model {}
/**
* @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');
}
}

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';
}