Compare commits

...

4 Commits

Author SHA1 Message Date
4d00f10274 Mappers 2023-06-26 10:49:25 -04:00
42a97bb074 0.1.0 2022-06-13 21:36:52 -04:00
3580738273 Files 2021-12-25 23:17:15 -03:00
bbee033a8a Files 2021-11-30 22:33:41 -03:00
134 changed files with 3681 additions and 272 deletions

View File

@ -7,6 +7,6 @@ RUN docker-php-ext-install pdo pdo_mysql zip
RUN pecl install xdebug-3.1.1 \
&& docker-php-ext-enable xdebug
WORKDIR /code
WORKDIR /app/api
COPY --from=composer /usr/bin/composer /usr/bin/composer

View File

@ -0,0 +1,30 @@
<?php
namespace Incoviba\API\Common\Alias;
use Incoviba\API\Common\Define\Controller\Json;
use Incoviba\API\Common\Factory\Mapper as MapperFactory;
use Incoviba\Mapper\Mapper;
class Controller
{
use Json;
protected MapperFactory $mapperFactory;
public function __construct(MapperFactory $mapperFactory) {
$this->mapperFactory = $mapperFactory;
}
protected array $mappers;
public function getMapper(string $name): Mapper
{
if (!class_exists($name)) {
throw new \InvalidArgumentException("Mapper {$name} not found.");
}
if (!isset($this->mappers)) {
$this->mappers = [];
}
if (!isset($this->mappers[$name])) {
$this->mappers[$name] = $this->mapperFactory->get($name);
}
return $this->mappers[$name];
}
}

View File

@ -39,7 +39,7 @@ abstract class Model extends BaseModel implements ModelInterface {
}
return $definitions;
}
public function parentOf(string $child_class, array $definitions): ?array {
public function parentOf(string $child_class, array $definitions): bool|array {
$definitions = $this->validateDefinitions(
$definitions,
[Model::CHILD_KEY, Model::SELF_KEY],
@ -48,7 +48,7 @@ abstract class Model extends BaseModel implements ModelInterface {
$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): ?ModelInterface {
public function childOf(string $parent_class, array $definitions): bool|ModelInterface {
$definitions = $this->validateDefinitions(
$definitions,
[Model::PARENT_KEY, Model::SELF_KEY],
@ -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,76 @@
<?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\Service\Login as LoginService;
use Incoviba\Mapper\User as UserMapper;
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, LoginService $loginService, UserMapper $mapper): Response {
$post = json_decode($request->getBody());
$user = $mapper->fetchByName($post->name);
$output = [
'login' => false,
'token' => ''
];
if (!$user or !$user->enabled) {
return $this->withJson($response, $output);
}
if ($user->validate($post->password)) {
$token = $service->generateToken();
$status = $loginService->setToken($user, $token->selector, $token->token);
if ($status['logged_in']) {
$output['login'] = true;
$output['token'] = $token->full;
$output['expires'] = $status['expires'];
}
}
return $this->withJson($response, $output);
}
public function validate(Request $request, Response $response, LoginService $loginService): Response {
$post = json_decode($request->getBody());
$valid = $loginService->validate($post);
$output = [
'token' => $post->token
];
if ($valid) {
$output['status'] = 'Authorized';
} else {
$output['error'] = 'Not authorized';
}
return $this->withJson($response, $output, $valid ? 200 : 401);
}
public function user(Request $request, Response $response, LoginService $loginService): Response {
$post = json_decode($request->getBody());
$user = $loginService->getUser($post);
if (!$user) {
return $this->withJson($response, ['token' => $post->token, 'error' => 'Not authorized'], 401);
}
$output = [
'token' => $post->token,
'user' => $user->name
];
return $this->withJson($response, $output);
}
public function logout(Request $request, Response $response, LoginService $loginService): Response {
$post = json_decode($request->getBody());
$user = $loginService->getUser($post);
if (!$user) {
return $this->withJson($response, ['logout' => true]);
}
$output = [
'token' => $post->token,
'logout' => $loginService->logout($user)
];
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

@ -1,93 +1,184 @@
<?php
namespace Incoviba\API\Common\Controller;
use Carbon\Carbon;
use Incoviba\API\Common\Alias\Controller;
use Incoviba\Mapper\EstadoVenta;
use Incoviba\Mapper\ProyectoAgente;
use Incoviba\Mapper\TipoEstadoProyecto;
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;
use Incoviba\Mapper\Proyecto as ProyectoMapper;
use Incoviba\Mapper\EstadoProyecto;
use Incoviba\Mapper\Venta as VentaMapper;
use Incoviba\Mapper\ProyectoTipoUnidad as TipoMapper;
use Incoviba\Mapper\Unidad as UnidadMapper;
use Incoviba\Mapper\Precio as PrecioMapper;
use Incoviba\Mapper\EstadoPrecio as EstadoMapper;
use Incoviba\API\Common\Service\Format;
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;
class Proyectos extends Controller {
public function __invoke(Request $request, Response $response): Response {
$proyectos = $this->getMapper(ProyectoMapper::class)->fetchAll();
usort($proyectos, function($a, $b) {
return strcmp($a->descripcion, $b->descripcion);
});
$proyectos = json_decode(json_encode($proyectos), JSON_OBJECT_AS_ARRAY);
foreach ($proyectos as &$proyecto) {
$proyecto['ventas'] = $this->getMapper(VentaMapper::class)->fetchCountByProyecto($proyecto['id']);
}
return $this->withJson($response, compact('proyectos'));
}
public function show(Request $request, Response $response, $proyecto_id): Response {
$proyecto = $this->getMapper(ProyectoMapper::class)->fetchById($proyecto_id);
$output = [
'proyecto' => json_decode(json_encode($proyecto), JSON_OBJECT_AS_ARRAY)
];
return $this->withJson($response, $output);
}
public function add(Request $request, Response $response, Factory $factory): Response {
$post = $request->getParsedBody();
$output = [
'input' => $post
];
if (in_array('proyectos', $post)) {
$output['proyectos'] = [];
foreach ($post['proyectos'] as $input) {
$proyecto = Proyecto::add($factory, $input);
$proyecto []= [
'proyecto' => $proyecto->toArray(),
'created' => $proyecto->is_new() ? $proyecto->save() : false
];
}
} elseif (in_array('proyecto', $post)) {
$proyecto = Proyecto::add($factory, $post);
$output['proyecto'] = $proyecto;
$output['created'] = $proyecto->is_new() ? $proyecto->save() : false;
}
return $this->withJson($response, $output);
}
public function edit(Request $request, Response $response, Factory $factory, $proyecto_id): Response {
$post = $request->getParsedBody();
$input = compact('proyecto_id', 'post');
$proyecto = $factory->find(Proyecto::class)->one($proyecto_id);
$output = [
'input' => $input,
'proyecto' => $proyecto->toArray()
];
$output['edited'] = $proyecto->edit($post);
$output['changes'] = $proyecto->toArray();
return $this->withJson($response, $output);
}
public function delete(Request $request, Response $response, Factory $factory, $proyecto_id): Response {
$proyecto = $factory->find(Proyecto::class)->one($proyecto_id);
$output = [
'input' => $proyecto_id,
'proyecto' => $proyecto->toArray()
];
$output['deleted'] = $proyecto->delete();
return $this->withJson($response, $output);
}
public function ventas(Request $request, Response $response, int $proyecto_id): Response
{
$proyecto = $this->getMapper(ProyectoMapper::class)->fetchById($proyecto_id);
$ventas = $this->getMapper(VentaMapper::class)->fetchActivaByProyecto($proyecto_id);
$output = ['proyecto' => json_decode(json_encode($proyecto), JSON_OBJECT_AS_ARRAY)];
$output['proyecto']['ventas'] = json_decode(json_encode($ventas), JSON_OBJECT_AS_ARRAY);
foreach ($ventas as $i => $venta) {
$estado = $this->getMapper(EstadoVenta::class)->fetchLastByVenta($venta->id);
$output['proyecto']['ventas'][$i]['estado'] = $estado;
}
return $this->withJson($response, $output);
}
public function precios(Request $request, Response $response, Format $format, int $proyecto_id): Response {
$proyecto = $this->getMapper(ProyectoMapper::class)->fetchById($proyecto_id);
$output = json_decode(json_encode(compact('proyecto')), JSON_OBJECT_AS_ARRAY);
$tipos = $this->getMapper(TipoMapper::class)->fetchByProyecto($proyecto_id);
usort($tipos, function($a, $b) {
$t = strcmp($a->tipo->id, $b->tipo->id);
if ($t === 0) {
return strcmp($a->nombre, $b->nombre);
}
return $t;
});
$output['proyecto']['tipos'] = json_decode(json_encode($tipos), JSON_OBJECT_AS_ARRAY);
foreach ($tipos as $i => $tipo) {
$unidades = $this->getMapper(UnidadMapper::class)->fetchByTipo($tipo->id);
$output['proyecto']['tipos'][$i]['unidades'] = json_decode(json_encode($unidades), JSON_OBJECT_AS_ARRAY);
foreach ($unidades as $k => $unidad) {
if ($unidad->subtipo === null) {
$output['proyecto']['tipos'][$i]['unidades'][$k]['subtipo'] = $tipo->nombre;
}
$precio = $this->getMapper(PrecioMapper::class)->fetchLastByUnidad($unidad->id);
if (!$precio) {
$output['proyecto']['tipos'][$i]['unidades'][$k]['precio'] = ['valor' => 0, 'formateado' => 0, 'estado' => ['estado' => ['descripcion' => '']]];
continue;
}
$output['proyecto']['tipos'][$i]['unidades'][$k]['precio'] = json_decode(json_encode($precio), JSON_OBJECT_AS_ARRAY);
$output['proyecto']['tipos'][$i]['unidades'][$k]['precio']['estado'] = json_decode(json_encode($this->getMapper(EstadoMapper::class)->fetchLastByPrecio($precio->id)), JSON_OBJECT_AS_ARRAY);
$output['proyecto']['tipos'][$i]['unidades'][$k]['precio']['formateado'] = $format->uf($precio->valor);
}
}
return $this->withJson($response, $output);
}
public function estado(Request $request, Response $response, int $proyecto_id): Response
{
$proyecto = $this->getMapper(ProyectoMapper::class)->fetchById($proyecto_id);
$estado = $this->getMapper(EstadoProyecto::class)->fetchLastByProyecto($proyecto_id);
$output = [
'proyecto' => $proyecto,
'estado' => json_decode(json_encode($estado), JSON_OBJECT_AS_ARRAY)
];
$output['estado']['fecha']['diff'] = Carbon::createFromTimestamp($estado->fecha->getTimestamp())->locale('es-CL')->diffForHumans();
return $this->withJson($response, $output);
}
public function inicio(Request $request, Response $response, int $proyecto_id): Response
{
$proyecto = $this->getMapper(ProyectoMapper::class)->fetchById($proyecto_id);
$estado = $this->getMapper(EstadoProyecto::class)->fetchFirstByProyecto($proyecto_id);
$output = [
'proyecto' => $proyecto,
'estado' => json_decode(json_encode($estado), JSON_OBJECT_AS_ARRAY)
];
$output['estado']['fecha']['diff'] = Carbon::createFromTimestamp($estado->fecha->getTimestamp())->locale('es-CL')->diffForHumans();
if ($estado->fecha->getTimestamp() < 0) {
$output['estado']['fecha']['diff'] = '-';
}
return $this->withJson($response, $output);
}
public function progreso(Request $request, Response $response, int $proyecto_id): Response
{
$proyecto = $this->getMapper(ProyectoMapper::class)->fetchById($proyecto_id);
$inicio = $this->getMapper(EstadoProyecto::class)->fetchFirstByProyecto($proyecto_id);
$estado = $this->getMapper(EstadoProyecto::class)->fetchLastByProyecto($proyecto_id);
$orden_tipo_estados = array_map(function($item) {
return $item->orden;
}, $this->getMapper(TipoEstadoProyecto::class)->fetchAll());
$estados = $this->getMapper(EstadoProyecto::class)->fetchByProyecto($proyecto_id);
$total = 1;
if ($estado->tipo->orden < max($orden_tipo_estados) - 1 and count($estados) > 1) {
$tf = Carbon::createFromTimestamp($estado->fecha->getTimestamp());
$t0 = Carbon::createFromTimestamp($inicio->fecha->getTimestamp());
$df = $tf->diffInSeconds($t0);
$hoy = Carbon::now();
$dh = $hoy->diffInSeconds($t0);
$total = $df / $dh;
}
$valor = round(($estado->tipo->orden + 1) / max($orden_tipo_estados) * 100 * $total);
$output = [
'proyecto' => $proyecto,
'progreso' => $valor
];
return $this->withJson($response, $output);
}
public function operadores(Request $request, Response $response, int $proyecto_id): Response
{
$proyecto = $this->getMapper(ProyectoMapper::class)->fetchById($proyecto_id);
$operadores = $this->getMapper(ProyectoAgente::class)->fetchOperadoresVigenteByProyecto($proyecto_id);
$output = compact('proyecto', 'operadores');
return $this->withJson($response, $output);
}
return $this->withJson($response, $output);
}
public function edit(Request $request, Response $response, Factory $factory, $proyecto_id): Response {
$post = $request->getParsedBody();
$input = compact('proyecto_id', 'post');
$proyecto = $factory->find(Proyecto::class)->one($proyecto_id);
$output = [
'input' => $input,
'proyecto' => $proyecto->toArray()
];
$output['edited'] = $proyecto->edit($post);
$output['changes'] = $proyecto->toArray();
return $this->withJson($response, $output);
}
public function delete(Request $request, Response $response, Factory $factory, $proyecto_id): Response {
$proyecto = $factory->find(Proyecto::class)->one($proyecto_id);
$output = [
'input' => $proyecto_id,
'proyecto' => $proyecto->toArray()
];
$output['deleted'] = $proyecto->delete();
return $this->withJson($response, $output);
}
}

View File

@ -0,0 +1,38 @@
<?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\Define\Controller\Json;
use Incoviba\Mapper\Proyecto as ProyectoMapper;
use Incoviba\Mapper\Cierre as CierreMapper;
class Cierres {
use Json;
public function __invoke(Request $request, Response $response, ProyectoMapper $proyectoMapper, CierreMapper $cierreMapper): Response {
$proyectos = $proyectoMapper->fetchAll();
$cierres = [];
function filter_cierres($cierres, $estado) {
return array_filter($cierres, function ($item) use ($estado) {
return $item->estado()->tipo->descripcion === $estado;
});
}
foreach ($proyectos as $proyecto) {
$cs = $cierreMapper->fetchByProyecto($proyecto->id);
if (count($cs) == 0) {
continue;
}
$pendientes = filter_cierres($cs, 'pendiente');
$cierres[$proyecto->descripcion] = [
'proyecto' => $proyecto->descripcion,
'total' => count($cs),
'promesados' => count(filter_cierres($cs, 'promesado')),
'rechazados' => count(filter_cierres($cs, 'rechazado')),
'pendientes' => count($pendientes),
'ultimo_pendiente' => (count($pendientes) > 0) ? $pendientes[0]->periodo() : 0
];
}
return $this->withJson($response, compact('cierres'));
}
}

View File

@ -0,0 +1,57 @@
<?php
namespace Incoviba\API\Common\Controller\Proyectos;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Carbon\Carbon;
use Incoviba\Proyecto\Proyecto;
use Incoviba\API\Common\Define\Controller\Json;
use Incoviba\API\Common\Factory\Model as Factory;
use Incoviba\Mapper\Proyecto as ProyectoMapper;
use Incoviba\Mapper\Cuota as CuotaMapper;
class Cuotas {
use Json;
public function mes(Request $request, Response $response, ProyectoMapper $proyectoMapper, CuotaMapper $cuotaMapper): Response {
$proyectos = $proyectoMapper->fetchAll();
$dias = [];
foreach ($proyectos as $proyecto) {
$cuotas = $cuotaMapper->fetchByProyectoAndMes($proyecto->id, new \DateTimeImmutable());
foreach ($cuotas as $cuota) {
$f = Carbon::createFromTimestamp($cuota->pago->fecha->getTimestamp());
if ($f->isoWeekday() == 6 or $f->isoWeekDay() == 7) {
$f = $f->copy()->addDays(2)->startOfWeek();
}
$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, ['dias' => $dias]);
}
public function hoy(Request $request, Response $response, ProyectoMapper $proyectoMapper, CuotaMapper $cuotaMapper): Response {
$proyectos = $proyectoMapper->fetchAll();
$hoy = 0;
foreach ($proyectos as $proyecto) {
$hoy += count($cuotaMapper->fetchByProyectoAndFecha($proyecto->id, new \DateTimeImmutable()));
}
return $this->withJson($response, ['hoy' => $hoy]);
}
public function pendientes(Request $request, Response $response, ProyectoMapper $proyectoMapper, CuotaMapper $cuotaMapper): Response {
$proyectos = $proyectoMapper->fetchAll();
$pendientes = 0;
foreach ($proyectos as $proyecto) {
$pendientes += count($cuotaMapper->fetchByProyectoAndPendiente($proyecto->id));
}
return $this->withJson($response, ['pendientes' => $pendientes]);
}
}

View File

@ -6,87 +6,153 @@ use Psr\Http\Message\ResponseInterface as Response;
use Incoviba\API\Common\Define\Controller\Json;
use Incoviba\API\Common\Factory\Model as Factory;
use Incoviba\Venta\Venta;
use Incoviba\Mapper\Venta as VentaMapper;
class Ventas {
use Json;
use Json;
public function __invoke(Request $request, Response $response, Factory $factory): Response {
$ventas = $factory->find(Venta::class)->array();
$url = '' . $request->getUri();
array_walk($ventas, function (&$item) use ($url) {
$item['link'] = [
'rel' => 'venta',
'title' => 'Venta',
'href' => str_replace('/ventas', "/venta/{$item['id']}", $url)
];
});
return $this->withJson($response, compact('ventas'));
}
public function show(Request $request, Response $response, Factory $factory, $venta_id): Response {
$venta = $factory->find(Venta::class)->one($venta_id);
$output = [
'input' => $venta_id,
'venta' => $venta->toArray(),
'link' => [
'rel' => 'ventas',
'title' => 'Ventas',
'href' => str_replace("/venta/{$venta_id}", '/ventas', $request->getUri())
]
];
$output['links'] = [
[
'rel' => 'propietario',
'title' => $venta->propietario()->nombreCompleto(),
'href' => str_replace("/venta/{$venta_id}", "/propietario/{$venta->propietario}", $request->getUri())
],
[
'rel' => 'propiedad',
'title' => 'Propiedad',
'href' => str_replace("/venta/{$venta_id}", "/propiedad/{$venta->propiedad}", $request->getUri())
]
];
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;
public function __invoke(Request $request, Response $response, Factory $factory, VentaMapper $mapper): Response {
$ventas = $mapper->fetchAll();
error_log(var_export($ventas, true));
$ventas = $factory->find(Venta::class)->array();
$url = '' . $request->getUri();
array_walk($ventas, function (&$item) use ($url) {
$item['link'] = [
'rel' => 'venta',
'title' => 'Venta',
'href' => str_replace('/ventas', "/venta/{$item['id']}", $url)
];
});
return $this->withJson($response, compact('ventas'));
}
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);
}
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

@ -21,7 +21,7 @@ interface Model {
* @param array $definitions array of conditions for connecting to the child table
* @return array|null
*/
public function parentOf(string $child_class, array $definitions): ?array;
public function parentOf(string $child_class, array $definitions): bool|array;
/**
* Get parent model of class {$parent_class}
@ -29,7 +29,7 @@ interface Model {
* @param array $definitions array of conditions for connecting to the parent table
* @return Model|null
*/
public function childOf(string $parent_class, array $definitions): ?Model;
public function childOf(string $parent_class, array $definitions): bool|Model;
/**
* Get all siblings of class {$sibling_class}
@ -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

22
common/Factory/Mapper.php Normal file
View File

@ -0,0 +1,22 @@
<?php
namespace Incoviba\API\Common\Factory;
use Incoviba\Mapper\Mapper as BaseMapper;
use Psr\Container\ContainerInterface;
class Mapper
{
protected ContainerInterface $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function get(string $name): BaseMapper
{
if (!class_exists($name)) {
throw new \InvalidArgumentException();
}
return $this->container->get($name);
}
}

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

14
common/Service/Format.php Normal file
View File

@ -0,0 +1,14 @@
<?php
namespace Incoviba\API\Common\Service;
class Format
{
public function uf(float $number)
{
return number_format($number, 2, ',', '.');
}
public function pesos(float $number)
{
return number_format($number, 0, ',', '.');
}
}

90
common/Service/Login.php Normal file
View File

@ -0,0 +1,90 @@
<?php
namespace Incoviba\API\Common\Service;
use Carbon\Carbon;
use Incoviba\Mapper\User as UserMapper;
use Incoviba\Mapper\Login as LoginMapper;
use Incoviba\Mapper\Config as ConfigMapper;
use Incoviba\Model\Auth\User;
class Login
{
protected UserMapper $userMapper;
protected LoginMapper $loginMapper;
protected ConfigMapper $configMapper;
public function __construct(UserMapper $userMapper, LoginMapper $loginMapper, ConfigMapper $configMapper)
{
$this->userMapper = $userMapper;
$this->loginMapper = $loginMapper;
$this->configMapper = $configMapper;
}
public function setToken(User $user, string $selector, string $token)
{
$this->logout($user);
$expiration = $this->configMapper->fetchByName('cookie_expiration_time');
$data = [
'user_id' => $user->id,
'time' => (new \DateTimeImmutable())->format('Y-m-d H:i:s '),
'selector' => $selector,
'token' => $token,
'status' => 1
];
$status = false;
try {
$login = $this->loginMapper->create($data);
$status = $this->loginMapper->save($login);
} catch (\PDOException $e) {
$login = false;
}
$output = [
'input' => $data,
'login' => $login,
'logged_in' => $status
];
if ($login !== false) {
$output['expires'] = $login->time->modify("+{$expiration->value} second")->getTimestamp();
}
return $output;
}
public function logout(User $user): bool
{
$logins = $this->validLogins($user);
if ($logins === false or count($logins) === 0) {
return true;
}
$bool = true;
foreach ($logins as $login) {
$login->status = false;
$bool &= $this->loginMapper->save($login);
}
return $bool;
}
public function validLogins(User $user): bool|array {
return $this->loginMapper->fetchActiveByUser($user->id);
}
public function validate($request): bool
{
list($selector, $token) = explode(':', $request->token);
$login = $this->loginMapper->fetchBySelector($selector);
if (!$login or !$login->status or !password_verify($token, $login->token)) {
return false;
}
$expiration = $this->configMapper->fetchByName('cookie_expiration_time');
if ((Carbon::createFromTimestamp($login->time->getTimestamp()))->diffInSeconds() > $expiration->value) {
$login->status = false;
$this->loginMapper->save($login);
return false;
}
return true;
}
public function getUser($request): User|bool
{
list($selector, $token) = explode(':', $request->token);
$login = $this->loginMapper->fetchBySelector($selector);
if (!$login or !$login->status) {
return false;
}
return $login->user;
}
}

View File

@ -7,7 +7,7 @@
"zeuxisoo/slim-whoops": "^0.7.3",
"slim/psr7": "^1.5",
"nesbot/carbon": "^2.54",
"j4mie/paris": "^1.5"
"doctrine/dbal": "^3.3"
},
"require-dev": {
"phpunit/phpunit": "^9.5",

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

@ -1,16 +1,30 @@
server {
listen 80;
listen 81;
server_name api;
index index.php;
error_log /code/logs/error.log;
access_log /code/logs/access.log;
root /code/public;
error_log /var/log/nginx/api.error.log;
access_log /var/log/nginx/api.access.log;
root /app/api/public;
location / {
try_files $uri /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,7 +1,12 @@
<?php
include_once implode(DIRECTORY_SEPARATOR, [
$app = include_once implode(DIRECTORY_SEPARATOR, [
dirname(__FILE__, 2),
'setup',
'app.php'
]);
$app->run();
try {
$app->run();
} catch (Error | Exception $e) {
error_log($e);
echo json_encode(['message' => 'There was an error', 'error' => $e->getMessage(), 'errorCode' => $e->getCode()]);
}

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,12 +1,28 @@
<?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->get('[/]', Proyectos::class);
$app->post('/add[/]', [Proyectos::class, 'add']);
$app->group('/cuotas', function($app) {
$app->get('/hoy[/]', [Cuotas::class, 'hoy']);
$app->get('/mes[/]', [Cuotas::class, 'mes']);
$app->get('/pendientes[/]', [Cuotas::class, 'pendientes']);
});
$app->group('/cierres', function($app) {
$app->get('[/]', Cierres::class);
});
$app->get('[/]', Proyectos::class);
});
$app->group('/proyecto/{proyecto_id}', function ($app) {
$app->put('/edit[/]', [Proyectos::class, 'edit']);
$app->delete('/edit[/]', [Proyectos::class, 'delete']);
$app->get('[/]', [Proyectos::class, 'show']);
$app->get('/ventas', [Proyectos::class, 'ventas']);
$app->get('/precios', [Proyectos::class, 'precios']);
$app->get('/inicio', [Proyectos::class, 'inicio']);
$app->get('/estado', [Proyectos::class, 'estado']);
$app->get('/progreso', [Proyectos::class, 'progreso']);
$app->get('/operadores', [Proyectos::class, 'operadores']);
$app->put('/edit[/]', [Proyectos::class, 'edit']);
$app->delete('/delete[/]', [Proyectos::class, 'delete']);
$app->get('[/]', [Proyectos::class, 'show']);
});

View File

@ -49,5 +49,7 @@ if (file_exists($folder)) {
$app->addRoutingMiddleware();
include_once 'databases.php';
//include_once 'databases.php';
include_once 'router.php';
return $app;

View File

@ -5,7 +5,7 @@ foreach ($database->databases as $name => $settings) {
switch (strtolower($settings->engine)) {
case 'mysql':
$dsn = "mysql:host={$settings->host->name};dbname={$settings->name}" . (isset($settings->host->port) ? ';port=' . $settings->host->port : '');
ORM::configure([
Orm::configure([
'connection_string' => $dsn,
'username' => $settings->user->name,
'password' => $settings->user->password
@ -13,12 +13,12 @@ foreach ($database->databases as $name => $settings) {
break;
}
if (isset($settings->logging) and $settings->logging) {
ORM::configure('logging', true, $name);
Orm::configure('logging', true, $name);
}
if (isset($settings->caching) and $settings->caching) {
ORM::configure('caching', true, $name);
Orm::configure('caching', true, $name);
}
}
if (isset($database->short_names) and $database->short_names) {
Model::$short_table_names = true;
Orm::$short_table_names = true;
}

View File

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

View File

@ -4,6 +4,7 @@ return [
$arr = [
'default' => (object) [
'engine' => 'mysql',
'driver' => 'pdo_mysql',
'host' => (object) [
'name' => $_ENV['MYSQL_HOST'] ?? 'db'
],

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(

View File

@ -0,0 +1,19 @@
<?php
use Psr\Container\ContainerInterface;
return [
\Doctrine\DBAL\Connection::class => function(ContainerInterface $container) {
$config = $container->get('database')->databases['default'];
$conn = [
'dbname' => $config->name,
'user' => $config->user->name,
'password' => $config->user->password,
'host' => $config->host->name,
'driver' => $config->driver
];
if (isset($config->host->port)) {
$conn['port'] = $config->host->port;
}
return \Doctrine\DBAL\DriverManager::getConnection($conn);
}
];

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

26
src/Mapper/Agente.php Normal file
View File

@ -0,0 +1,26 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Proyecto\Agente as BaseModel;
class Agente extends Mapper
{
protected string $table = 'agente';
protected function load(bool|array $row, bool $lazy = false): BaseModel|bool
{
$model = new BaseModel();
$model->id = $row['id'];
$model->rut = $row['rut'];
$model->descripcion = $row['descripcion'];
$model->abreviacion = $row['abreviacion'];
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

25
src/Mapper/AgenteTipo.php Normal file
View File

@ -0,0 +1,25 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Proyecto\AgenteTipo as AgenteModel;
class AgenteTipo extends Mapper
{
protected string $table = 'agente_tipo';
protected function load(bool|array $row, bool $lazy = false): AgenteModel|bool
{
$model = new AgenteModel();
$model->id = $row['id'];
$model->agente = $this->getMapper(Agente::class)->fetchById($row['agente']);
$model->tipo = $this->getMapper(TipoAgente::class)->fetchById($row['tipo']);
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

25
src/Mapper/Banco.php Normal file
View File

@ -0,0 +1,25 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Common\Banco as BancoModel;
class Banco extends Mapper
{
protected string $table = 'banco';
protected function load(bool|array $row, bool $lazy = false): BancoModel|bool
{
if (!$row) return false;
$model = new BancoModel();
$model->id = $row['id'];
$model->nombre = $row['nombre'];
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

22
src/Mapper/BonoPie.php Normal file
View File

@ -0,0 +1,22 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\BonoPie as BaseModel;
class BonoPie extends Mapper
{
protected string $table = 'bono_pie';
protected function load(bool|array $row, bool $lazy = false): BaseModel|bool
{
$model = new BaseModel();
$model->id = $row['id'];
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

38
src/Mapper/Cierre.php Normal file
View File

@ -0,0 +1,38 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\Cierre as CierreModel;
class Cierre extends Mapper
{
protected string $table = 'cierre';
protected function load(bool|array $row, bool $lazy = false): CierreModel|bool
{
if (!$row) return false;
$model = new CierreModel();
$model->id = $row['id'];
$model->proyecto = $this->getMapper(Proyecto::class)->fetchById($row['proyecto']);
$model->precio = $row['precio'];
$model->fecha = new \DateTimeImmutable($row['fecha']);
$model->relacionado = $row['relacionado'] != 0;
$model->propietario = $row['propietario'] == 0 ? 0 : $this->getMapper(Propietario::class)->fetchById($row['propietario']);
$model->setFactory($this->factory);
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
public function fetchByProyecto(int $proyecto_id): array
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where('proyecto = ?');
return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$proyecto_id])->fetchAllAssociative());
}
}

25
src/Mapper/Comuna.php Normal file
View File

@ -0,0 +1,25 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Common\Comuna as BaseModel;
class Comuna extends Mapper
{
protected string $table = 'comuna';
protected function load(bool|array $row, bool $lazy = false): BaseModel|bool
{
$model = new BaseModel();
$model->id = $row['id'];
$model->descripcion = $row['descripcion'];
// $model->provincia = $this->getMapper(Provincia::class)->fetchById($row['provincia']);
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

33
src/Mapper/Config.php Normal file
View File

@ -0,0 +1,33 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Admin\Config as ConfigModel;
use Incoviba\Model\Model;
class Config extends Mapper
{
protected string $table = 'configurations';
protected function load(array|bool $row, bool $lazy = false): ConfigModel|bool
{
if (!$row) return false;
$model = new ConfigModel();
$model->id = $row['id'];
$model->name = $row['name'];
$model->value = $row['value'];
return $model;
}
public function save(Model $model): bool
{
return true;
}
public function fetchByName(string $name): ConfigModel
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where('name = ?');
return $this->load(($this->connection->executeQuery($qb, [$name]))->fetchAssociative());
}
}

22
src/Mapper/Credito.php Normal file
View File

@ -0,0 +1,22 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\Credito as CreditoModel;
class Credito extends Mapper
{
public string $table = 'credito';
protected function load(bool|array $row, bool $lazy = false): CreditoModel|bool
{
$credito = new CreditoModel();
$credito->id = $row['id'];
return $credito;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

93
src/Mapper/Cuota.php Normal file
View File

@ -0,0 +1,93 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\Cuota as CuotaModel;
class Cuota extends Mapper
{
protected string $table = 'cuota';
protected function load(bool|array $row, bool $lazy = false): CuotaModel|bool
{
if (!$row) return false;
$model = new CuotaModel();
$model->id = $row['id'];
$model->pie = $this->getMapper(Pie::class)->fetchById($row['pie']);
$model->fecha = new \DateTimeImmutable($row['fecha']);
$model->valor = $row['valor_$'];
$model->estado = $row['estado'];
$model->banco = ($row['banco'] != '') ? $this->getMapper(Banco::class)->fetchById($row['banco']) : null;
$estado = new CuotaModel\Estado();
$estado->fecha_pago = ($row['fecha_pago']) ? new \DateTimeImmutable($row['fecha_pago']) : null;
$estado->abonado = $row['abonado'];
$estado->fecha_abono = ($row['fecha_abono']) ? new \DateTimeImmutable($row['fecha_abono']) : null;
$model->estado_cuota = $estado;
$model->uf = $row['uf'];
$model->pago = $this->getMapper(Pago::class)->fetchById($row['pago']);
$model->numero = $row['numero'];
return $model;
}
public function save(Model $model): bool
{
return true;
}
public function fetchByProyecto(int $proyecto_id): array
{
$qb = $this->connection->createQueryBuilder()
->select('a.*')
->from($this->table, 'a')
->innerJoin('a', 'venta', 'v', 'v.pie = a.pie')
->innerJoin('v', 'propiedad', 'p', 'p.id = v.propiedad')
->innerJoin('p', 'unidad', 'u', 'u.id = p.unidad_principal')
->innerJoin('u', 'proyecto_tipo_unidad', 'ptu', 'ptu.id = u.pt')
->where('ptu.proyecto = ?');
return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$proyecto_id])->fetchAllAssociative());
}
public function fetchByProyectoAndFecha(int $proyecto_id, \DateTimeInterface $fecha): array
{
$qb = $this->connection->createQueryBuilder()
->select('a.*')
->from($this->table, 'a')
->innerJoin('a', 'venta', 'v', 'v.pie = a.pie')
->innerJoin('v', 'propiedad', 'p', 'p.id = v.propiedad')
->innerJoin('p', 'unidad', 'u', 'u.id = p.unidad_principal')
->innerJoin('u', 'proyecto_tipo_unidad', 'ptu', 'ptu.id = u.pt')
->innerJoin('a', 'pago', 'g', 'g.id = a.pago')
->where('ptu.proyecto = ?')
->andWhere('g.fecha = ?');
return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$proyecto_id, $fecha->format('y-m-d')])->fetchAllAssociative());
}
public function fetchByProyectoAndMes(int $proyecto_id, \DateTimeInterface $mes): array
{
$qb = $this->connection->createQueryBuilder()
->select('a.*')
->from($this->table, 'a')
->innerJoin('a', 'venta', 'v', 'v.pie = a.pie')
->innerJoin('v', 'propiedad', 'p', 'p.id = v.propiedad')
->innerJoin('p', 'unidad', 'u', 'u.id = p.unidad_principal')
->innerJoin('u', 'proyecto_tipo_unidad', 'ptu', 'ptu.id = u.pt')
->innerJoin('a', 'pago', 'g', 'g.id = a.pago')
->where('ptu.proyecto = ?')
->andWhere('g.fecha BETWEEN ? AND ?');
return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$proyecto_id, $mes->format('y-m-1'), $mes->format('y-m-t')])->fetchAllAssociative());
}
public function fetchByProyectoAndPendiente(int $proyecto_id): array
{
$qb = $this->connection->createQueryBuilder()
->select('a.*')
->from($this->table, 'a')
->innerJoin('a', 'venta', 'v', 'v.pie = a.pie')
->innerJoin('v', 'propiedad', 'p', 'p.id = v.propiedad')
->innerJoin('p', 'unidad', 'u', 'u.id = p.unidad_principal')
->innerJoin('u', 'proyecto_tipo_unidad', 'ptu', 'ptu.id = u.pt')
->innerJoin('a', 'pago', 'g', 'g.id = a.pago')
->leftJoin('g', '(SELECT e1.* FROM estado_pago e1 JOIN (SELECT MAX(id) AS id, pago FROM estado_pago GROUP BY pago) e0 ON e0.id = e1.id)', 'ep', 'ep.pago = g.id')
->where('ptu.proyecto = ?')
->andWhere('ep.estado < 1')
->andWhere('ep.estado >= 0');
return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$proyecto_id])->fetchAllAssociative());
}
}

28
src/Mapper/Direccion.php Normal file
View File

@ -0,0 +1,28 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Common\Direccion as DireccionModel;
class Direccion extends Mapper
{
protected string $table = 'direccion';
protected function load(bool|array $row, bool $lazy = false): DireccionModel|bool
{
if (!$row) return false;
$model = new DireccionModel();
$model->id = $row['id'];
$model->calle = $row['calle'];
$model->numero = $row['numero'];
$model->extra = $row['extra'];
$model->comuna = $this->getMapper(Comuna::class)->fetchById($row['comuna']);
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

23
src/Mapper/Entrega.php Normal file
View File

@ -0,0 +1,23 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\Entrega as BaseModel;
class Entrega extends Mapper
{
protected string $table = 'entrega';
protected function load(bool|array $row, bool $lazy = false): BaseModel|bool
{
$model = new BaseModel();
$model->id = $row['id'];
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

21
src/Mapper/Escritura.php Normal file
View File

@ -0,0 +1,21 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\Escritura as EscrituraModel;
class Escritura extends Mapper
{
protected string $table = 'escritura';
protected function load(bool|array $row, bool $lazy = false): EscrituraModel|bool
{
$escritura = new EscrituraModel();
$escritura->id = $row['id'];
return $escritura;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\EstadoCierre as EstadoModel;
class EstadoCierre extends Mapper
{
protected string $table = 'estado_cierre';
protected function load(bool|array $row, bool $lazy = false): EstadoModel|bool
{
if (!$row) return false;
$model = new EstadoModel();
$model->id = $row['id'];
$model->fecha = new \DateTimeImmutable($row['fecha']);
$model->tipo = $this->getMapper(TipoEstadoCierre::class)->fetchById($row['tipo']);
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
public function fetchLastByCierre(int $cierre_id)
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where('cierre = ?')
->orderBy('id', 'desc')
->setMaxResults(1);
return $this->load($this->connection->executeQuery($qb, [$cierre_id])->fetchAssociative(), true);
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\EstadoPrecio as EstadoModel;
class EstadoPrecio extends Mapper
{
protected string $table = 'estado_precio';
protected function load(bool|array $row, bool $lazy = false): EstadoModel|bool
{
if (!$row) return false;
$model = new EstadoModel();
$model->id = $row['id'];
$model->fecha = new \DateTimeImmutable($row['fecha']);
$model->estado = $this->getMapper(TipoEstadoPrecio::class)->fetchById($row['estado']);
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
public function fetchByPrecio(int $precio_id): array
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where('precio = ?');
return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$precio_id])->fetchAllAssociative());
}
public function fetchLastByPrecio(int $precio_id): EstadoModel|bool
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where('precio = ?')
->setMaxResults(1)
->orderBy('id', 'desc');
return $this->load($this->connection->executeQuery($qb, [$precio_id])->fetchAssociative());
}
}

View File

@ -0,0 +1,55 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Proyecto\EstadoProyecto as BaseModel;
class EstadoProyecto extends Mapper
{
protected string $table = 'estado_proyecto';
protected function load(bool|array $row, bool $lazy = false): BaseModel|bool
{
$model = new BaseModel();
$model->id = $row['id'];
$model->proyecto = $this->getMapper(Proyecto::class)->fetchById($row['proyecto']);
$model->tipo = $this->getMapper(TipoEstadoProyecto::class)->fetchById($row['estado']);
$model->fecha = new \DateTimeImmutable($row['fecha']);
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
public function fetchByProyecto(int $proyecto_id): array
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where('proyecto = ?');
return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$proyecto_id])->fetchAllAssociative());
}
public function fetchLastByProyecto(int $proyecto_id): BaseModel|bool
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where('proyecto = ?')
->setMaxResults(1)
->orderBy('id', 'desc');
return $this->load($this->connection->executeQuery($qb, [$proyecto_id])->fetchAssociative());
}
public function fetchFirstByProyecto(int $proyecto_id): BaseModel|bool
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where('proyecto = ?')
->setMaxResults(1)
->orderBy('id', 'asc');
return $this->load($this->connection->executeQuery($qb, [$proyecto_id])->fetchAssociative());
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\EstadoVenta as BaseModel;
class EstadoVenta extends Mapper
{
protected string $table = 'estado_venta';
protected function load(bool|array $row, bool $lazy = false): BaseModel|bool
{
$model = new BaseModel();
$model->id = $row['id'];
$model->estado = $this->getMapper(TipoEstadoVenta::class)->fetchById($row['estado']);
$model->fecha = new \DateTimeImmutable($row['fecha']);
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
public function fetchByVenta(int $venta_id): array
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where('venta = ?');
return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$venta_id])->fetchAllAssociative());
}
public function fetchLastByVenta(int $venta_id): BaseModel|bool
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where('venta = ?')
->setMaxResults(1)
->orderBy('id', 'desc');
return $this->load($this->connection->executeQuery($qb, [$venta_id])->fetchAssociative());
}
}

25
src/Mapper/Etapa.php Normal file
View File

@ -0,0 +1,25 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Proyecto\Etapa as BaseModel;
class Etapa extends Mapper
{
protected string $table = 'etapa_proyecto';
protected function load(bool|array $row, bool $lazy = false): BaseModel|bool
{
$model = new BaseModel();
$model->id = $row['id'];
$model->descripcion = $row['descripcion'];
$model->orden = $row['orden'];
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Inmobiliaria\Inmobiliaria as InmobiliariaModel;
class Inmobiliaria extends Mapper
{
protected string $id = 'rut';
protected string $table = 'inmobiliaria';
protected function load(bool|array $row, bool $lazy = false): InmobiliariaModel|bool
{
if (!$row) return false;
$model = new InmobiliariaModel();
$model->rut = $row['rut'];
$model->dv = $row['dv'];
$model->razon = $row['razon'];
$model->abreviacion = $row['abreviacion'];
$model->cuenta = $row['cuenta'];
$model->banco = ($row['banco']) ? $this->getMapper(Banco::class)->fetchById($row['banco']) : null;
$model->sociedad = $row['sociedad'];
return $model;
}
public function save(Model $model): bool
{
return false;
}
}

82
src/Mapper/Login.php Normal file
View File

@ -0,0 +1,82 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Auth\Login as LoginModel;
use Incoviba\Model\Model;
class Login extends Mapper
{
protected string $table = 'logins';
public function load(array|bool $row, bool $lazy = false): LoginModel|bool
{
if (!$row) return false;
$model = new LoginModel();
if (isset($row['id'])) {
$model->id = (int) $row['id'];
}
if (!$lazy) {
$model->user = $this->getMapper(User::class)->fetchById((int) $row['user_id']);
}
$model->time = new \DateTimeImmutable($row['time']);
$model->selector = $row['selector'];
$model->token = $row['token'];
$model->status = $row['status'] != 0;
return $model;
}
public function save(Model $model): bool
{
if (!isset($model->id)) {
$qb = $this->connection->createQueryBuilder()
->insert($this->table)
->values([
'user_id' => '?',
'time' => '?',
'selector' => '?',
'token' => '?',
'status' => '?'
]);
return $this->connection->executeStatement($qb, [
$model->user->id,
$model->time->format('Y-m-d H:i:s'),
$model->selector,
$model->token,
$model->status ? 1 : 0
]) > 0;
}
$qb = $this->connection->createQueryBuilder()
->update($this->table)
->set('user_id', '?')
->set('time', '?')
->set('selector', '?')
->set('token', '?')
->set('status', '?')
->where('id = ?');
return $this->connection->executeStatement($qb, [
$model->user->id,
$model->time->format('Y-m-d H:i:s'),
$model->selector,
$model->token,
$model->status ? 1 : 0,
$model->id
]) > 0;
}
public function fetchActiveByUser(int $user_id): array
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where('user_id = ?')
->andWhere('status = 1');
return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$user_id])->fetchAllAssociative());
}
public function fetchBySelector(string $selector): LoginModel|bool
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where('selector = ?');
return $this->load($this->connection->executeQuery($qb, [$selector])->fetchAssociative());
}
}

80
src/Mapper/Mapper.php Normal file
View File

@ -0,0 +1,80 @@
<?php
namespace Incoviba\Mapper;
use Doctrine\DBAL\Connection;
use Incoviba\Model\Model;
use Psr\Container\ContainerInterface;
use Incoviba\API\Common\Factory\Mapper as Factory;
abstract class Mapper
{
protected Connection $connection;
protected array $mappers;
protected Factory $factory;
public function __construct(ContainerInterface $container)
{
$this->factory = $container->get(Factory::class);
$this->connection = $container->get(Connection::class);
}
protected string $id = 'id';
protected string $table = '';
public function fetch(string $name, array $params = [])
{
$method = 'fetch' . str_replace(' ', '', ucwords(str_replace('_', ' ', $name)));
if (method_exists($this, $method)) {
return call_user_func_array([$this, $method], $params);
}
throw new \InvalidArgumentException("Method {$method} not found in " . get_called_class());
}
public function fetchById(int $id): Model|bool
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where("{$this->id} = ?");
$row = $this->connection->executeQuery($qb, [$id])->fetchAssociative();
return $this->load($row);
}
public function fetchAll(): array
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table);
$row = $this->connection->executeQuery($qb)->fetchAllAssociative();
return array_map([$this, 'load'], $row);
}
public function getMapper(string $name): Mapper
{
if (!class_exists($name)) {
throw new \InvalidArgumentException("Mapper {$name} does not exist");
}
if (!isset($this->mappers)) {
$this->mappers = [];
}
if (!isset($this->mappers[$name])) {
$this->mappers[$name] = $this->factory->get($name);
}
return $this->mappers[$name];
}
public function create(array $data): Model|bool
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table);
foreach (array_keys($data) as $field) {
$qb = $qb->andWhere("{$field} = ?");
}
$row = ($this->connection->executeQuery($qb, array_values($data)))->fetchAssociative();
if (!$row) {
$row = $data;
}
return $this->load($row);
}
abstract protected function load(array|bool $row, bool $lazy = false): Model|bool;
abstract public function save(Model $model): bool;
}

32
src/Mapper/Pago.php Normal file
View File

@ -0,0 +1,32 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\Pago as PagoModel;
class Pago extends Mapper
{
protected string $table = 'pago';
protected function load(bool|array $row, bool $lazy = false): PagoModel|bool
{
if (!$row) return false;
$model = new PagoModel();
$model->id = $row['id'];
$model->valor = $row['valor'];
$model->banco = ($row['banco']) ? $this->getMapper(Banco::class)->fetchById($row['banco']) : null;
$model->tipo = $this->getMapper(TipoPago::class)->fetchById($row['tipo']);
$model->identificador = $row['identificador'];
$model->fecha = new \DateTimeImmutable($row['fecha']);
$model->uf = $row['uf'];
$model->pagador = $row['pagador'];
$model->asociado = ($row['asociado']) ? $this->fetchById($row['asociado']) : null;
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

23
src/Mapper/Pie.php Normal file
View File

@ -0,0 +1,23 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\Pie as PieModel;
class Pie extends Mapper
{
protected string $table = 'pie';
protected function load(bool|array $row, bool $lazy = false): PieModel|bool
{
if (!$row) return false;
$model = new PieModel();
$model->id = $row['id'];
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

43
src/Mapper/Precio.php Normal file
View File

@ -0,0 +1,43 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\Precio as PrecioModel;
class Precio extends Mapper
{
protected string $table = 'precio';
protected function load(bool|array $row, bool $lazy = false): PrecioModel|bool
{
if (!$row) return false;
$model = new PrecioModel();
$model->id = $row['id'];
$model->valor = $row['valor'];
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
public function fetchByUnidad(int $unidad_id): array
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where('unidad = ?');
return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$unidad_id])->fetchAllAssociative());
}
public function fetchLastByUnidad(int $unidad_id): PrecioModel|bool
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where('unidad = ?')
->orderBy('id', 'desc')
->setMaxResults(1);
return $this->load($this->connection->executeQuery($qb, [$unidad_id])->fetchAssociative());
}
}

22
src/Mapper/Promocion.php Normal file
View File

@ -0,0 +1,22 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\Promocion as PromocionModel;
class Promocion extends Mapper
{
protected string $table = 'promocion';
protected function load(bool|array $row, bool $lazy = false): PromocionModel|bool
{
$model = new PromocionModel();
$model->id = $row['id'];
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

24
src/Mapper/Propiedad.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\Propiedad as PropiedadModel;
class Propiedad extends Mapper
{
protected string $table = 'propiedad';
protected function load(bool|array $row, bool $lazy = false): PropiedadModel|bool
{
$propiedad = new PropiedadModel();
$propiedad->id = $row['id'];
$propiedad->estado = $row['estado'] != 0;
$propiedad->unidades = $this->getMapper(Unidad::class)->fetchByPropiedad($row['id']);
return $propiedad;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\Propietario as PropietarioModel;
class Propietario extends Mapper
{
protected string $id = 'rut';
protected string $table = 'propietario';
protected function load(bool|array $row, bool $lazy = false): PropietarioModel|bool
{
if (!$row) return false;
$model = new PropietarioModel();
$model->rut = $row['rut'];
$model->nombres = $row['nombres'];
$model->setApellidos($row['apellido_paterno'], $row['apellido_materno']);
$datos = new PropietarioModel\Datos();
$datos->sexo = $row['sexo'];
$datos->estado_civil = $row['estado_civil'];
$datos->profesion = $row['profesion'];
$datos->direccion = $row['direccion'] == 0 ? $this->getMapper(Direccion::class)->fetchById($row['direccion']) : 0;
$datos->telefono = $row['telefono'];
$datos->email = $row['email'];
$model->datos = $datos;
$model->repesentante = $row['representante'];
$model->otro = $row['otro'];
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

35
src/Mapper/Proyecto.php Normal file
View File

@ -0,0 +1,35 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Proyecto\Proyecto as ProyectoModel;
class Proyecto extends Mapper
{
protected string $table = 'proyecto';
protected function load(bool|array $row, bool $lazy = false): ProyectoModel|bool
{
if (!$row) return false;
$model = new ProyectoModel();
$model->id = $row['id'];
$model->inmobiliaria = $this->getMapper(Inmobiliaria::class)->fetchById($row['inmobiliaria']);
$model->descripcion = $row['descripcion'];
$model->direccion = $this->getMapper(Direccion::class)->fetchById($row['direccion']);
$model->valor_terreno = $row['valor_terreno'];
$superficie = new ProyectoModel\Superficie();
$superficie->terreno = $row['superficie_terreno'];
$superficie->bajo_nivel = $row['superficie_bajo_nivel'];
$superficie->sobre_nivel = $row['superficie_sobre_nivel'];
$model->superficie = $superficie;
$model->corredor = $row['corredor'];
$model->pisos = $row['pisos'];
$model->subterraneos = $row['subterraneos'];
return $model;
}
public function save(Model $model): bool
{
return true;
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Proyecto\ProyectoAgente as AgenteModel;
class ProyectoAgente extends Mapper
{
protected string $table = 'proyecto_agente';
protected function load(bool|array $row, bool $lazy = false): AgenteModel|bool
{
$model = new AgenteModel();
$model->id = $row['id'];
$model->proyecto = $this->getMapper(Proyecto::class)->fetchById($row['proyecto']);
$model->agenteTipo = $this->getMapper(AgenteTipo::class)->fetchById($row['agente']);
$model->fecha = new \DateTimeImmutable($row['fecha']);
$model->comision = $row['comision'];
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
public function fetchOperadoresVigenteByProyecto(int $proyecto_id): array
{
$qb = $this->connection->createQueryBuilder()
->select('pa.*')
->from($this->table, 'pa')
->innerJoin('pa', 'agente_tipo', 'at', 'at.id = pa.agente')
->innerJoin('at', 'tipo_agente', 'ta', 'ta.id = at.tipo')
->innerJoin('pa', '(SELECT e1.* FROM estado_proyecto_agente e1 JOIN (SELECT MAX(id) AS id, agente FROM estado_proyecto_agente GROUP BY agente) e0 ON e0.id = e1.id)', 'ep', 'ep.agente = pa.id')
->innerJoin('ep', 'tipo_estado_proyecto_agente', 'tep', 'tep.id = ep.tipo')
->where('pa.proyecto = ?')
->andWhere('ta.descripcion = ?')
->andWhere('tep.descripcion = ?');
return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$proyecto_id, 'operador', 'vigente'])->fetchAllAssociative());
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Proyecto\ProyectoTipoUnidad as TipoModel;
class ProyectoTipoUnidad extends Mapper
{
protected string $table = 'proyecto_tipo_unidad';
protected function load(bool|array $row, bool $lazy = false): TipoModel|bool
{
if (!$row) return false;
$model = new TipoModel();
$model->id = $row['id'];
$model->proyecto = $this->getMapper(Proyecto::class)->fetchById($row['proyecto']);
$model->tipo = $this->getMapper(TipoUnidad::class)->fetchById($row['tipo']);
$model->abreviacion = $row['abreviacion'];
$model->nombre = $row['nombre'];
$supreficie = new TipoModel\Superficie();
$supreficie->interior = $row['m2'];
$supreficie->logia = $row['logia'];
$supreficie->terraza = $row['terraza'];
$model->superficie = $supreficie;
$model->descripcion = $row['descripcion'];
$model->tipologias = $this->getMapper(TipoTipologia::class)->fetchByPTU($row['id']);
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
public function fetchByProyecto(int $proyecto_id): array
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where('proyecto = ?');
return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$proyecto_id])->fetchAllAssociative());
}
}

22
src/Mapper/Subsidio.php Normal file
View File

@ -0,0 +1,22 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\Subsidio as BaseModel;
class Subsidio extends Mapper
{
protected string $table = 'subsidio';
protected function load(bool|array $row, bool $lazy = false): BaseModel|bool
{
$model = new BaseModel();
$model->id = $row['id'];
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

24
src/Mapper/TipoAgente.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Proyecto\TipoAgente as BaseModel;
class TipoAgente extends Mapper
{
protected string $table = 'tipo_agente';
protected function load(bool|array $row, bool $lazy = false): BaseModel|bool
{
$model = new BaseModel();
$model->id = $row['id'];
$model->descripcion = $row['descripcion'];
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Proyecto\TipoElemento as BaseModel;
class TipoElemento extends Mapper
{
protected string $table = 'tipo_elemento';
protected function load(bool|array $row, bool $lazy = false): BaseModel|bool
{
$model = new BaseModel();
$model->id = $row['id'];
$model->descripcion = $row['descripcion'];
$model->abreviacion = $row['abreviacion'];
$model->orden = $row['orden'];
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\TipoEstadoCierre as TipoModel;
class TipoEstadoCierre extends Mapper
{
protected string $table = 'tipo_estado_cierre';
protected function load(bool|array $row, bool $lazy = false): TipoModel|bool
{
if (!$row) return false;
$model = new TipoModel();
$model->id = $row['id'];
$model->descripcion = $row['descripcion'];
$model->vigente = $row['vigente'] !== 0;
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\TipoEstadoPrecio as TipoModel;
class TipoEstadoPrecio extends Mapper
{
protected string $table = 'tipo_estado_precio';
protected function load(bool|array $row, bool $lazy = false): TipoModel|bool
{
$model = new TipoModel();
$model->id = $row['id'];
$model->descripcion = $row['descripcion'];
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Proyecto\TipoEstadoProyecto as BaseModel;
class TipoEstadoProyecto extends Mapper
{
protected string $table = 'tipo_estado_proyecto';
protected function load(bool|array $row, bool $lazy = false): BaseModel|bool
{
$model = new BaseModel();
$model->id = $row['id'];
$model->descripcion = $row['descripcion'];
$model->orden = $row['orden'];
$model->etapa = $this->getMapper(Etapa::class)->fetchById($row['etapa']);
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\TipoEstadoVenta as BaseModel;
class TipoEstadoVenta extends Mapper
{
protected string $table = 'tipo_estado_venta';
protected function load(bool|array $row, bool $lazy = false): BaseModel|bool
{
$model = new BaseModel();
$model->id = $row['id'];
$model->descripcion = $row['descripcion'];
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

23
src/Mapper/TipoPago.php Normal file
View File

@ -0,0 +1,23 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\TipoPago as TipoModel;
class TipoPago extends Mapper
{
protected string $table = 'tipo_pago';
protected function load(bool|array $row, bool $lazy = false): TipoModel|bool
{
if (!$row) return false;
$model = new TipoModel();
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Proyecto\TipoTipologia as BaseModel;
class TipoTipologia extends Mapper
{
protected string $table = 'tipo_tipologia';
protected function load(bool|array $row, bool $lazy = false): BaseModel|bool
{
$model = new BaseModel();
$model->id = $row['id'];
$model->tipologia = $this->getMapper(Tipologia::class)->fetchById($row['tipologia']);
$model->cantidad = $row['cantidad'];
$model->elemento = $this->getMapper(TipoElemento::class)->fetchById($row['elemento']);
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
public function fetchByPTU(int $ptu_id): array
{
$qb = $this->connection->createQueryBuilder()
->select('tt.*')
->from($this->table, 'tt')
->innerJoin('tt', 'tipo_elemento', 'te', 'te.id = tt.elemento')
->where('tt.tipo = ?')
->orderBy('te.orden');
return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$ptu_id])->fetchAllAssociative());
}
}

25
src/Mapper/TipoUnidad.php Normal file
View File

@ -0,0 +1,25 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Proyecto\TipoUnidad as TipoModel;
class TipoUnidad extends Mapper
{
protected string $table = 'tipo_unidad';
protected function load(bool|array $row, bool $lazy = false): TipoModel|bool
{
if (!$row) return false;
$model = new TipoModel();
$model->id = $row['id'];
$model->descripcion = $row['descripcion'];
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

24
src/Mapper/Tipologia.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Proyecto\Tipologia as BaseModel;
class Tipologia extends Mapper
{
protected string $table = 'tipologia';
protected function load(bool|array $row, bool $lazy = false): BaseModel|bool
{
$model = new BaseModel();
$model->id = $row['id'];
$model->descripcion = $row['descripcion'];
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
}

46
src/Mapper/Unidad.php Normal file
View File

@ -0,0 +1,46 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Proyecto\Unidad as UnidadModel;
class Unidad extends Mapper
{
protected string $table = 'unidad';
protected function load(bool|array $row, bool $lazy = false): UnidadModel|bool
{
$model = new UnidadModel();
$model->id = $row['id'];
$model->subtipo = $row['subtipo'];
$model->piso = $row['piso'];
$model->descripcion = $row['descripcion'];
$model->abreviacion = $row['abreviacion'];
$model->orientacion = $row['orientacion'];
$model->proyectoTipoUnidad = $this->getMapper(ProyectoTipoUnidad::class)->fetchById($row['pt']);
return $model;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
public function fetchByTipo(int $tipo_id): array
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where('pt = ?');
return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$tipo_id])->fetchAllAssociative());
}
public function fetchByPropiedad(int $propiedad_id): array
{
$qb = $this->connection->createQueryBuilder()
->select('u.*')
->from($this->table, 'u')
->innerJoin('u', 'propiedad_unidad', 'pu', 'pu.unidad = u.id')
->where('pu.propiedad = ?');
return array_map([$this, 'load'], $this->connection->executeQuery($qb, [$propiedad_id])->fetchAllAssociative());
}
}

54
src/Mapper/User.php Normal file
View File

@ -0,0 +1,54 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Auth\User as UserModel;
use Incoviba\Model\Model;
class User extends Mapper
{
protected string $table = 'users';
protected function load(array|bool $row, bool $lazy = false): UserModel|bool
{
if (!$row) return false;
$model = new UserModel();
$model->id = $row['id'];
$model->name = $row['name'];
$model->setPassword($row['password']);
$model->enabled = $row['enabled'] != 0;
return $model;
}
public function save(Model $model): bool
{
if (isset($model->id)) {
$qb = $this->connection->createQueryBuilder()
->insert($this->table)
->values([
'name' => $model->name,
'password' => $model->getPassword(),
'enabled' => $model->enabled ? 1 : 0
]);
return $this->connection->executeStatement($qb) > 0;
}
$qb = $this->connection->createQueryBuilder()
->update($this->table)
->set('name', $model->name)
->set('password', $model->getPassword())
->set('enabled', $model->enabled ? 1 : 0)
->where('id = ?');
return $this->connection->executeStatement($qb, [$model->id]) > 0;
}
public function fetchByName(string $name): UserModel|bool
{
$qb = $this->connection->createQueryBuilder()
->select('*')
->from($this->table)
->where('name = ?');
return $this->load(
$this->connection
->executeQuery($qb, [$name])
->fetchAssociative()
);
}
}

97
src/Mapper/Venta.php Normal file
View File

@ -0,0 +1,97 @@
<?php
namespace Incoviba\Mapper;
use Incoviba\Model\Model;
use Incoviba\Model\Venta\Venta as VentaModel;
class Venta extends Mapper
{
protected string $table = 'venta';
public function load(array|bool $row, bool $lazy = false): VentaModel|bool
{
if (!$row) return false;
$venta = new VentaModel();
$venta->id = $row['id'];
$venta->propietario = $this->getMapper(Propietario::class)->fetchById($row['propietario']);
$venta->propiedad = $this->getMapper(Propiedad::class)->fetchById($row['propiedad']);
$venta->fecha = new \DateTimeImmutable($row['fecha']);
$venta->valor = $row['valor_uf'];
$venta->estado = $row['estado'];
$venta->fecha_ingreso = new \DateTimeImmutable($row['fecha_ingreso']);
$venta->uf = $row['uf'];
$forma_pago = new VentaModel\FormaPago();
$forma_pago->pie = $row['pie'] ? $this->getMapper(Pie::class)->fetchById($row['pie']) : null;
$forma_pago->bonoPie = $row['bono_pie'] ? $this->getMapper(BonoPie::class)->fetchById($row['bono_pie']) : null;
$forma_pago->escritura = $row['escritura'] ? $this->getMapper(Escritura::class)->fetchById($row['escritura']) : null;
$forma_pago->credito = $row['credito'] ? $this->getMapper(Credito::class)->fetchById($row['credito']) : null;
$forma_pago->subsidio = $row['subsidio'] ? $this->getMapper(Subsidio::class)->fetchById($row['subsidio']) : null;
$venta->formaPago = $forma_pago;
$estado = new VentaModel\Estado();
$estado->escriturado = $row['escriturado'] ? new \DateTimeImmutable($row['escriturado']) : null;
$estado->entrega = $row['entrega'] ? $this->getMapper(Entrega::class)->fetchById($row['entrega']) : null;
$estado->entregado = $row['entregado'] ? new \DateTimeImmutable($row['entregado']) : null;
$venta->estado_venta = $estado;
$datos = new VentaModel\Datos();
$datos->avalchile = $row['avalchile'] != 0;
$datos->agente = $row['agente'] ? $this->getMapper(ProyectoAgente::class)->fetchById($row['agente']) : null;
$datos->relacionado = $row['relacionado'] != 0;
$datos->promocion = $row['promocion'] ? $this->getMapper(Promocion::class)->fetchById($row['promocion']) : null;
$datos->resciliacion = $row['resciliacion'] ? $this->getMapper(Pago::class)->fetchById($row['resciliacion']) : null;
$datos->devolucion = $row['devolucion'] ? $this->getMapper(Pago::class)->fetchById($row['devolucion']) : null;
$venta->datos = $datos;
$venta->setFactory($this->factory);
return $venta;
}
public function save(Model $model): bool
{
// TODO: Implement save() method.
}
public function fetchByProyecto(int $proyecto_id): array
{
$qb = $this->connection->createQueryBuilder();
$qb->select('a.*')
->from($this->table, 'a')
->innerJoin('a', 'propiedad', 'p', 'p.id = a.propiedad')
->innerJoin('p', 'unidad', 'u', 'u.id = p.unidad_principal')
->innerJoin('u', 'proyecto', 'o', 'o.id = u.proyecto')
->where("o.id = ?")
->orderBy("LPAD(u.descripcion, 4, '0')");
$row = $this->connection->executeQuery($qb, [$proyecto_id])->fetchAllAssociative();
return array_map([$this, 'load'], $row);
}
public function fetchActivaByProyecto(int $proyecto_id): array
{
$qb = $this->connection->createQueryBuilder();
$qb->select('v.*')
->from($this->table, 'v')
->innerJoin('v', 'propiedad', 'p', 'p.id = v.propiedad')
->innerJoin('p', 'unidad', 'u', 'u.id = p.unidad_principal')
->innerJoin('u', 'proyecto', 'o', 'o.id = u.proyecto')
->innerJoin('v', '(SELECT e1.* FROM estado_venta e1 JOIN (SELECT MAX(id) AS id, venta FROM estado_venta GROUP BY venta) e0 ON e0.id = e1.id)', 'ev', 'ev.venta = v.id')
->innerJoin('ev', 'tipo_estado_venta', 'tev', 'tev.id = ev.estado')
->where("o.id = ?")
->andWhere('tev.activa = 1')
->orderBy("LPAD(u.descripcion, 4, '0')");
$row = $this->connection->executeQuery($qb, [$proyecto_id])->fetchAllAssociative();
return array_map([$this, 'load'], $row);
}
public function fetchCountByProyecto(int $proyecto_id): int|bool
{
$qb = $this->connection->createQueryBuilder();
$qb->select("COUNT(v.id) AS 'cantidad'")
->from($this->table, 'v')
->innerJoin('v', 'propiedad', 'p', 'p.id = v.propiedad')
->innerJoin('p', 'unidad', 'u', 'u.id = p.unidad_principal')
->innerJoin('u', 'proyecto', 'o', 'o.id = u.proyecto')
->innerJoin('v', '(SELECT e1.* FROM estado_venta e1 JOIN (SELECT MAX(id) AS id, venta FROM estado_venta GROUP BY venta) e0 ON e0.id = e1.id)', 'ev', 'ev.venta = v.id')
->innerJoin('ev', 'tipo_estado_venta', 'tev', 'tev.id = ev.estado')
->where("o.id = ?")
->andWhere('tev.activa = 1')
->groupBy('o.id');
$row = $this->connection->executeQuery($qb, [$proyecto_id])->fetchAssociative();
return $row ? $row['cantidad'] : false;
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace Incoviba\Model\Admin;
class Config extends \Incoviba\Model\Model
{
public int $id;
public string $name;
public string $value;
}

14
src/Model/Auth/Login.php Normal file
View File

@ -0,0 +1,14 @@
<?php
namespace Incoviba\Model\Auth;
use Incoviba\Model\Model;
class Login extends Model
{
public int $id;
public bool|User $user;
public \DateTimeInterface $time;
public string $selector;
public string $token;
public bool $status;
}

25
src/Model/Auth/User.php Normal file
View File

@ -0,0 +1,25 @@
<?php
namespace Incoviba\Model\Auth;
use Incoviba\Model\Model;
class User extends Model
{
public int $id;
public string $name;
protected string $password;
public bool $enabled;
public function setPassword(string $password): User
{
$this->password = $password;
return $this;
}
public function getPassword(): string
{
return $this->password;
}
public function validate($password): bool {
return password_verify($password, $this->password);
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace Incoviba\Model\Common;
class Banco extends \Incoviba\Model\Model
{
public int $id;
public string $nombre;
public function jsonSerialize(): array
{
return [
'id' => $this->id,
'nombre' => $this->nombre
];
}
}

View File

@ -0,0 +1,10 @@
<?php
namespace Incoviba\Model\Common;
class Comuna extends \Incoviba\Model\Model
{
public int $id;
public string $descripcion;
// public bool|Provincia $provincia;
}

View File

@ -0,0 +1,30 @@
<?php
namespace Incoviba\Model\Common;
class Direccion extends \Incoviba\Model\Model
{
public int $id;
public string $calle;
public int $numero;
public string $extra;
public bool|Comuna $comuna;
public function completa(): string
{
$str = implode(' ', [$this->calle, $this->numero]);
if ($this->extra != '') {
$str .= ' ' . $this->extra;
}
if ($this->comuna) {
$str .= ', ' . $this->comuna->descripcion;
}
return $str;
}
public function jsonSerialize(): mixed
{
$arr = parent::jsonSerialize();
$arr['completa'] = $this->completa();
return $arr;
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace Incoviba\Model\Inmobiliaria;
use Incoviba\Model\Common\Banco;
class Inmobiliaria extends \Incoviba\Model\Model
{
public int $rut;
public string $dv;
public string $razon;
public string $abreviacion;
public ?string $cuenta;
public ?Banco $banco;
public int $sociedad;
}

34
src/Model/Model.php Normal file
View File

@ -0,0 +1,34 @@
<?php
namespace Incoviba\Model;
use Incoviba\API\Common\Factory\Mapper as Factory;
use Incoviba\Mapper\Mapper;
abstract class Model implements \JsonSerializable
{
protected array $mappers;
protected Factory $factory;
public function setFactory(Factory $factory): Model
{
$this->factory = $factory;
return $this;
}
public function getMapper(string $name): Mapper
{
if (!class_exists($name)) {
throw new \InvalidArgumentException("Mapper {$name} not found.");
}
if (!isset($this->mappers)) {
$this->mappers = [];
}
if (!isset($this->mappers[$name])) {
$this->mappers[$name] = $this->factory->get($name);
}
return $this->mappers[$name];
}
public function jsonSerialize(): mixed
{
return (array) $this;
}
}

View File

@ -0,0 +1,12 @@
<?php
namespace Incoviba\Model\Proyecto;
class Agente extends \Incoviba\Model\Model
{
public int $id;
public ?int $rut;
public string $descripcion;
public string $representante;
public string $abreviacion;
}

View File

@ -0,0 +1,9 @@
<?php
namespace Incoviba\Model\Proyecto;
class AgenteTipo extends \Incoviba\Model\Model
{
public int $id;
public bool|Agente $agente;
public bool|TipoAgente $tipo;
}

View File

@ -0,0 +1,11 @@
<?php
namespace Incoviba\Model\Proyecto;
class EstadoProyecto extends \Incoviba\Model\Model
{
public int $id;
public bool|Proyecto $proyecto;
public bool|TipoEstadoProyecto $tipo;
public \DateTimeInterface $fecha;
}

View File

@ -0,0 +1,10 @@
<?php
namespace Incoviba\Model\Proyecto;
class Etapa extends \Incoviba\Model\Model
{
public int $id;
public string $descripcion;
public int $orden;
}

View File

@ -0,0 +1,20 @@
<?php
namespace Incoviba\Model\Proyecto;
use Incoviba\Model\Common\Direccion;
use Incoviba\Model\Inmobiliaria\Inmobiliaria;
use Incoviba\Model\Model;
use Incoviba\Model\Proyecto\Proyecto\Superficie;
class Proyecto extends Model
{
public int $id;
public bool|Inmobiliaria $inmobiliaria;
public string $descripcion;
public bool|Direccion $direccion;
public float $valor_terreno;
public Superficie $superficie;
public float $corredor;
public int $pisos;
public int $subterraneos;
}

View File

@ -0,0 +1,18 @@
<?php
namespace Incoviba\Model\Proyecto\Proyecto;
class Superficie implements \JsonSerializable
{
public float $terreno;
public float $sobre_nivel;
public float $bajo_nivel;
public function jsonSerialize(): mixed
{
return [
'terreno' => $this->terreno,
'sobre_nivel' => $this->sobre_nivel,
'bajo_nivel' => $this->bajo_nivel
];
}
}

View File

@ -0,0 +1,12 @@
<?php
namespace Incoviba\Model\Proyecto;
class ProyectoAgente extends \Incoviba\Model\Model
{
public int $id;
public bool|Proyecto $proyecto;
public bool|AgenteTipo $agenteTipo;
public \DateTimeInterface $fecha;
public float $comision;
}

View File

@ -0,0 +1,37 @@
<?php
namespace Incoviba\Model\Proyecto;
use Incoviba\Model\Model;
use Incoviba\Model\Proyecto\ProyectoTipoUnidad\Superficie;
class ProyectoTipoUnidad extends Model
{
public int $id;
public bool|Proyecto $proyecto;
public bool|TipoUnidad $tipo;
public string $nombre;
public string $abreviacion;
public Superficie $superficie;
public string $descripcion;
public array $tipologias;
public function jsonSerialize(): array
{
$arr = parent::jsonSerialize();
$arr['tipologia'] = [
'abreviacion' => implode('/', array_map(function($tt) {
if (str_contains($tt->elemento->descripcion, 'cocina')) {
return $tt->elemento->abreviacion;
}
return $tt->cantidad . $tt->elemento->abreviacion;
}, $this->tipologias)),
'detalle' => implode(', ', array_map(function ($tt) {
if (str_contains($tt->elemento->descripcion, 'cocina')) {
return $tt->elemento->descripcion;
}
return $tt->cantidad . ' ' . $tt->elemento->descripcion . (($tt->cantidad > 0) ? 's' : '');
}, $this->tipologias))
];
return $arr;
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace Incoviba\Model\Proyecto\ProyectoTipoUnidad;
class Superficie implements \JsonSerializable
{
public float $interior;
public float $logia;
public float $terraza;
public function vendible()
{
return $this->interior + $this->logia + $this->terraza / 2;
}
public function jsonSerialize(): array
{
return [
'interior' => $this->interior,
'logia' => $this->logia,
'terraza' => $this->terraza,
'vendible' => $this->vendible()
];
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace Incoviba\Model\Proyecto;
class TipoAgente extends \Incoviba\Model\Model
{
public int $id;
public string $descripcion;
}

View File

@ -0,0 +1,11 @@
<?php
namespace Incoviba\Model\Proyecto;
class TipoElemento extends \Incoviba\Model\Model
{
public int $id;
public string $descripcion;
public string $abreviacion;
public int $orden;
}

View File

@ -0,0 +1,11 @@
<?php
namespace Incoviba\Model\Proyecto;
class TipoEstadoProyecto extends \Incoviba\Model\Model
{
public int $id;
public string $descripcion;
public int $orden;
public bool|Etapa $etapa;
}

View File

@ -0,0 +1,11 @@
<?php
namespace Incoviba\Model\Proyecto;
class TipoTipologia extends \Incoviba\Model\Model
{
public int $id;
public bool|ProyectoTipoUnidad $tipo;
public bool|Tipologia $tipologia;
public int $cantidad;
public bool|TipoElemento $elemento;
}

View File

@ -0,0 +1,8 @@
<?php
namespace Incoviba\Model\Proyecto;
class TipoUnidad extends \Incoviba\Model\Model
{
public int $id;
public string $descripcion;
}

View File

@ -0,0 +1,8 @@
<?php
namespace Incoviba\Model\Proyecto;
class Tipologia extends \Incoviba\Model\Model
{
public int $id;
public string $descripcion;
}

View File

@ -0,0 +1,22 @@
<?php
namespace Incoviba\Model\Proyecto;
class Unidad extends \Incoviba\Model\Model
{
public int $id;
public ?string $subtipo;
public int $piso;
public string $descripcion;
public string $abreviacion;
public ?string $orientacion;
public bool|ProyectoTipoUnidad $proyectoTipoUnidad;
public function jsonSerialize(): array
{
$arr = parent::jsonSerialize();
$arr['proyecto'] = $this->proyectoTipoUnidad->proyecto->jsonSerialize();
$arr['tipo'] = $this->proyectoTipoUnidad->tipo->jsonSerialize();
$arr['superficie'] = $this->proyectoTipoUnidad->superficie->jsonSerialize();
return $arr;
}
}

View File

@ -0,0 +1,10 @@
<?php
namespace Incoviba\Model\Venta;
use Incoviba\Model\Model;
class BonoPie extends Model
{
public int $id;
}

View File

@ -0,0 +1,25 @@
<?php
namespace Incoviba\Model\Venta;
use Incoviba\Mapper\EstadoCierre as EstadoMapper;
use Incoviba\Model\Proyecto\Proyecto;
class Cierre extends \Incoviba\Model\Model
{
public int $id;
public Proyecto $proyecto;
public float $precio;
public \DateTimeInterface $fecha;
public bool $relacionado;
public int|Propietario $propietario;
protected EstadoCierre $estadoCierre;
public function estado(): EstadoCierre
{
if (!isset($this->estadoCierre)) {
$this->estadoCierre = $this->mappers[EstadoMapper::class]->fetchLastByCierre($this->id);
}
return $this->estadoCierre;
}
}

Some files were not shown because too many files have changed in this diff Show More