Compare commits
7 Commits
61448a2521
...
9d2504f016
Author | SHA1 | Date | |
---|---|---|---|
9d2504f016 | |||
8ef4ab1c7d | |||
10b2485cfd | |||
0382f8c286 | |||
a3311f805e | |||
378de3ed86 | |||
69c2cffa6c |
1
.api.env.sample
Normal file
1
.api.env.sample
Normal file
@ -0,0 +1 @@
|
||||
API_KEY=
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -13,3 +13,5 @@
|
||||
|
||||
# Python
|
||||
**/.idea/
|
||||
|
||||
**/uploads/
|
||||
|
1
.python.env.sample
Normal file
1
.python.env.sample
Normal file
@ -0,0 +1 @@
|
||||
PYTHON_KEY=
|
@ -1,8 +1,8 @@
|
||||
FROM php:8-fpm
|
||||
|
||||
RUN apt-get update -y && apt-get install -y git libzip-dev zip
|
||||
RUN apt-get update -y && apt-get install -y git libzip-dev zip libpng-dev libfreetype6-dev libjpeg62-turbo-dev tesseract-ocr
|
||||
|
||||
RUN docker-php-ext-install pdo pdo_mysql zip
|
||||
RUN docker-php-ext-configure gd --with-freetype --with-jpeg && docker-php-ext-install pdo pdo_mysql zip gd
|
||||
|
||||
COPY --from=composer /usr/bin/composer /usr/bin/composer
|
||||
|
||||
|
6
api/common/Alias/DocumentHandler.php
Normal file
6
api/common/Alias/DocumentHandler.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Alias;
|
||||
|
||||
interface DocumentHandler {
|
||||
public function load(): ?array;
|
||||
}
|
11
api/common/Concept/DocumentHandler.php
Normal file
11
api/common/Concept/DocumentHandler.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Concept;
|
||||
|
||||
use Contabilidad\Common\Alias\DocumentHandler as HandlerInterface;
|
||||
|
||||
abstract class DocumentHandler implements HandlerInterface {
|
||||
protected string $folder;
|
||||
public function __construct(string $source_folder) {
|
||||
$this->folder = $source_folder;
|
||||
}
|
||||
}
|
@ -11,4 +11,17 @@ class Base {
|
||||
public function __invoke(Request $request, Response $response): Response {
|
||||
return $this->withJson($response, []);
|
||||
}
|
||||
public function generate_key(Request $request, Response $response): Response {
|
||||
$server_addr = explode('.', $request->getServerParams()['SERVER_ADDR']);
|
||||
$remote_addr = explode('.', $request->getServerParams()['REMOTE_ADDR']);
|
||||
for ($i = 0; $i < 3; $i ++) {
|
||||
if ($server_addr[$i] != $remote_addr[$i]) {
|
||||
throw new \InvalidArgumentException('Invalid connection address.');
|
||||
}
|
||||
}
|
||||
$salt = mt_rand();
|
||||
$signature = hash_hmac('sha256', $salt, 'contabilidad', true);
|
||||
$key = urlencode(base64_encode($signature));
|
||||
return $this->withJson($response, ['key' => $key]);
|
||||
}
|
||||
}
|
||||
|
@ -5,13 +5,34 @@ use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use ProVM\Common\Define\Controller\Json;
|
||||
use ProVM\Common\Factory\Model as Factory;
|
||||
use Contabilidad\Common\Service\TiposCambios as Service;
|
||||
use Contabilidad\Categoria;
|
||||
|
||||
class Categorias {
|
||||
use Json;
|
||||
|
||||
public function __invoke(Request $request, Response $response, Factory $factory): Response {
|
||||
$categorias = $factory->find(Categoria::class)->array();
|
||||
public function __invoke(Request $request, Response $response, Factory $factory, Service $service): Response {
|
||||
$categorias = $factory->find(Categoria::class)->many();
|
||||
array_walk($categorias, function(&$item) use ($service) {
|
||||
$arr = $item->toArray();
|
||||
$arr['cuentas'] = array_map(function($item) {
|
||||
return $item->toArray();
|
||||
}, $item->cuentas());
|
||||
$maps = ['activo', 'pasivo', 'ganancia', 'perdida'];
|
||||
foreach ($maps as $m) {
|
||||
$p = $m . 's';
|
||||
$t = ucfirst($m);
|
||||
$cuentas = $item->getCuentasOf($t);
|
||||
if ($cuentas === false or $cuentas === null) {
|
||||
$arr[$p] = 0;
|
||||
continue;
|
||||
}
|
||||
$arr[$p] = array_reduce($cuentas, function($sum, $item) use($service) {
|
||||
return $sum + $item->saldo($service, true);
|
||||
});
|
||||
}
|
||||
$item = $arr;
|
||||
});
|
||||
if ($categorias) {
|
||||
usort($categorias, function($a, $b) {
|
||||
return strcmp($a['nombre'], $b['nombre']);
|
||||
@ -68,14 +89,14 @@ class Categorias {
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function cuentas(Request $request, Response $response, Factory $factory, $categoria_id): Response {
|
||||
public function cuentas(Request $request, Response $response, Factory $factory, Service $service, $categoria_id): Response {
|
||||
$categoria = $factory->find(Categoria::class)->one($categoria_id);
|
||||
$cuentas = null;
|
||||
if ($categoria !== null) {
|
||||
$cuentas = $categoria->cuentas();
|
||||
if ($cuentas !== null) {
|
||||
array_walk($cuentas, function(&$item) {
|
||||
$item = $item->toArray();
|
||||
array_walk($cuentas, function(&$item) use ($service) {
|
||||
$item = $item->toArray($service);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use ProVM\Common\Define\Controller\Json;
|
||||
use ProVM\Common\Factory\Model as Factory;
|
||||
use Contabilidad\Common\Service\TiposCambios as Service;
|
||||
use Contabilidad\Cuenta;
|
||||
|
||||
class Cuentas {
|
||||
@ -14,11 +15,15 @@ class Cuentas {
|
||||
$cuentas = $factory->find(Cuenta::class)->array();
|
||||
if ($cuentas) {
|
||||
usort($cuentas, function($a, $b) {
|
||||
$t = strcmp($a['tipo']['descripcion'], $b['tipo']['descripcion']);
|
||||
if ($t != 0) {
|
||||
return $t;
|
||||
}
|
||||
$c = strcmp($a['categoria']['nombre'], $b['categoria']['nombre']);
|
||||
if ($c == 0) {
|
||||
return strcmp($a['nombre'], $b['nombre']);
|
||||
if ($c != 0) {
|
||||
return $c;
|
||||
}
|
||||
return $c;
|
||||
return strcmp($a['nombre'], $b['nombre']);
|
||||
});
|
||||
}
|
||||
$output = [
|
||||
@ -90,15 +95,28 @@ class Cuentas {
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function transacciones(Request $request, Response $response, Factory $factory, $cuenta_id, $limit = null, $start = 0): Response {
|
||||
public function transacciones(Request $request, Response $response, Factory $factory, Service $service, $cuenta_id, $limit = null, $start = 0): Response {
|
||||
$cuenta = $factory->find(Cuenta::class)->one($cuenta_id);
|
||||
$transacciones = null;
|
||||
if ($cuenta !== null) {
|
||||
$transacciones = $cuenta->transacciones($limit, $start);
|
||||
if (count($transacciones)) {
|
||||
array_walk($transacciones, function(&$item) {
|
||||
$item = $item->toArray();
|
||||
});
|
||||
if (count($transacciones) > 0) {
|
||||
foreach ($transacciones as &$transaccion) {
|
||||
$arr = $transaccion->toArray();
|
||||
if ($cuenta->moneda()->codigo === 'CLP') {
|
||||
if ($transaccion->debito()->moneda()->codigo !== 'CLP' or $transaccion->credito()->moneda()->codigo !== 'CLP') {
|
||||
if ($transaccion->debito()->moneda()->codigo !== 'CLP') {
|
||||
$c = $transaccion->debito();
|
||||
} else {
|
||||
$c = $transaccion->credito();
|
||||
}
|
||||
$service->get($transaccion->fecha(), $c->moneda()->id);
|
||||
$arr['valor'] = $c->moneda()->cambiar($transaccion->fecha(), $transaccion->valor);
|
||||
$arr['valorFormateado'] = $cuenta->moneda()->format($arr['valor']);
|
||||
}
|
||||
}
|
||||
$transaccion = $arr;
|
||||
}
|
||||
}
|
||||
}
|
||||
$output = [
|
||||
|
@ -5,7 +5,7 @@ use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use ProVM\Common\Define\Controller\Json;
|
||||
use ProVM\Common\Factory\Model as Factory;
|
||||
use Contabilidad\Common\Service\PdfHandler;
|
||||
use Contabilidad\Common\Service\DocumentHandler as Handler;
|
||||
|
||||
class Import {
|
||||
use Json;
|
||||
@ -14,8 +14,8 @@ class Import {
|
||||
$post = $request->getParsedBody();
|
||||
return $this->withJson($response, $post);
|
||||
}
|
||||
public function uploads(Request $request, Response $response, PdfHandler $handler): Response {
|
||||
$output = $handler->load();
|
||||
public function uploads(Request $request, Response $response, Handler $handler): Response {
|
||||
$output = $handler->handle();
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
}
|
||||
|
71
api/common/Controller/Monedas.php
Normal file
71
api/common/Controller/Monedas.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Controller;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use ProVM\Common\Define\Controller\Json;
|
||||
use ProVM\Common\Factory\Model as Factory;
|
||||
use Contabilidad\Moneda;
|
||||
|
||||
class Monedas {
|
||||
use Json;
|
||||
|
||||
public function __invoke(Request $request, Response $response, Factory $factory): Response {
|
||||
$monedas = $factory->find(Moneda::class)->array();
|
||||
if ($monedas) {
|
||||
usort($monedas, function($a, $b) {
|
||||
return strcmp($a['denominacion'], $b['denominacion']);
|
||||
});
|
||||
}
|
||||
$output = [
|
||||
'monedas' => $monedas
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function show(Request $request, Response $response, Factory $factory, $moneda_id): Response {
|
||||
$moneda = $factory->find(Moneda::class)->one($moneda_id);
|
||||
$output = [
|
||||
'input' => $moneda_id,
|
||||
'moneda' => $moneda?->toArray()
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function add(Request $request, Response $response, Factory $factory): Response {
|
||||
$input = json_decode($request->getBody());
|
||||
$results = [];
|
||||
if (is_array($input)) {
|
||||
foreach ($input as $in) {
|
||||
$moneda = Moneda::add($factory, $in);
|
||||
$results []= ['moneda' => $moneda?->toArray(), 'agregado' => $moneda?->save()];
|
||||
}
|
||||
} else {
|
||||
$moneda = Moneda::add($factory, $input);
|
||||
$results []= ['moneda' => $moneda?->toArray(), 'agregado' => $moneda?->save()];
|
||||
}
|
||||
$output = [
|
||||
'input' => $input,
|
||||
'monedas' => $results
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function edit(Request $request, Response $response, Factory $factory, $moneda_id): Response {
|
||||
$moneda = $factory->find(Moneda::class)->one($moneda_id);
|
||||
$output = [
|
||||
'input' => $moneda_id,
|
||||
'old' => $moneda->toArray()
|
||||
];
|
||||
$input = json_decode($request->getBody());
|
||||
$moneda->edit($input);
|
||||
$output['moneda'] = $moneda->toArray();
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function delete(Request $request, Response $response, Factory $factory, $moneda_id): Response {
|
||||
$moneda = $factory->find(Moneda::class)->one($moneda_id);
|
||||
$output = [
|
||||
'input' => $moneda_id,
|
||||
'moneda' => $moneda->toArray(),
|
||||
'eliminado' => $moneda->delete()
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
}
|
95
api/common/Controller/TiposCambios.php
Normal file
95
api/common/Controller/TiposCambios.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Controller;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use ProVM\Common\Define\Controller\Json;
|
||||
use ProVM\Common\Factory\Model as Factory;
|
||||
use Contabilidad\Common\Service\TiposCambios as Service;
|
||||
use Contabilidad\TipoCambio;
|
||||
|
||||
class TiposCambios {
|
||||
use Json;
|
||||
|
||||
public function __invoke(Request $request, Response $response, Factory $factory): Response {
|
||||
$tipos = $factory->find(TipoCambio::class)->array();
|
||||
if ($tipos) {
|
||||
usort($tipos, function($a, $b) {
|
||||
return strcmp($a['fecha'], $b['fecha']);
|
||||
});
|
||||
}
|
||||
$output = [
|
||||
'tipos' => $tipos
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function show(Request $request, Response $response, Factory $factory, $tipo_id): Response {
|
||||
$tipo = $factory->find(TipoCambio::class)->one($tipo_id);
|
||||
$output = [
|
||||
'input' => $tipo_id,
|
||||
'tipo' => $tipo?->toArray()
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function add(Request $request, Response $response, Factory $factory): Response {
|
||||
$input = json_decode($request->getBody());
|
||||
$results = [];
|
||||
if (is_array($input)) {
|
||||
foreach ($input as $in) {
|
||||
$tipo = TipoCambio::add($factory, $in);
|
||||
$results []= ['tipo' => $tipo?->toArray(), 'agregado' => $tipo?->save()];
|
||||
}
|
||||
} else {
|
||||
$tipo = TipoCambio::add($factory, $input);
|
||||
$results []= ['tipo' => $tipo?->toArray(), 'agregado' => $tipo?->save()];
|
||||
}
|
||||
$output = [
|
||||
'input' => $input,
|
||||
'tipos' => $results
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function edit(Request $request, Response $response, Factory $factory, $tipo_id): Response {
|
||||
$tipo = $factory->find(TipoCambio::class)->one($tipo_id);
|
||||
$output = [
|
||||
'input' => $tipo_id,
|
||||
'old' => $tipo->toArray()
|
||||
];
|
||||
$input = json_decode($request->getBody());
|
||||
$tipo->edit($input);
|
||||
$output['tipo'] = $tipo->toArray();
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function delete(Request $request, Response $response, Factory $factory, $tipo_id): Response {
|
||||
$tipo = $factory->find(TipoCambio::class)->one($tipo_id);
|
||||
$output = [
|
||||
'input' => $tipo_id,
|
||||
'tipo' => $tipo->toArray(),
|
||||
'eliminado' => $tipo->delete()
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function obtain(Request $request, Response $response, Factory $factory, Service $service): Response {
|
||||
$post = $request->getParsedBody();
|
||||
$valor = $service->get($post['fecha'], $post['moneda_id']);
|
||||
if ($valor === null) {
|
||||
return $this->withJson($response, ['input' => $post, 'tipo' => null, 'error' => 'No se encontró valor']);
|
||||
}
|
||||
$data = [
|
||||
'fecha' => $post['fecha'],
|
||||
'desde_id' => $post['moneda_id'],
|
||||
'hasta_id' => 1,
|
||||
'valor' => $valor
|
||||
];
|
||||
$tipo = TipoCambio::add($factory, $data);
|
||||
if ($tipo !== false and $tipo->is_new()) {
|
||||
$tipo->save();
|
||||
}
|
||||
$output = [
|
||||
'input' => $post,
|
||||
'tipo' => $tipo?->toArray()
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
}
|
139
api/common/Controller/TiposCategorias.php
Normal file
139
api/common/Controller/TiposCategorias.php
Normal file
@ -0,0 +1,139 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Controller;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use ProVM\Common\Define\Controller\Json;
|
||||
use ProVM\Common\Factory\Model as Factory;
|
||||
use Contabilidad\Common\Service\TiposCambios as Service;
|
||||
use Contabilidad\TipoCategoria;
|
||||
|
||||
class TiposCategorias {
|
||||
use Json;
|
||||
|
||||
public function __invoke(Request $request, Response $response, Factory $factory, Service $service): Response {
|
||||
$tipos = $factory->find(TipoCategoria::class)->many();
|
||||
array_walk($tipos, function(&$item) use ($service) {
|
||||
$arr = $item->toArray();
|
||||
$arr['categorias'] = array_map(function($item) {
|
||||
return $item->toArray();
|
||||
}, $item->categorias());
|
||||
$arr['saldo'] = abs($item->saldo($service));
|
||||
$maps = ['activo', 'pasivo', 'ganancia', 'perdida'];
|
||||
foreach ($maps as $m) {
|
||||
$p = $m . 's';
|
||||
$t = ucfirst($m);
|
||||
$cuentas = $item->getCuentasOf($t);
|
||||
if ($cuentas === false or $cuentas === null) {
|
||||
$arr[$p] = 0;
|
||||
continue;
|
||||
}
|
||||
$arr[$p] = array_reduce($cuentas, function($sum, $item) use($service) {
|
||||
return $sum + $item->saldo($service, true);
|
||||
});
|
||||
}
|
||||
$item = $arr;
|
||||
});
|
||||
if ($tipos) {
|
||||
usort($tipos, function($a, $b) {
|
||||
return strcmp($a['descripcion'], $b['descripcion']);
|
||||
});
|
||||
}
|
||||
$output = [
|
||||
'tipos' => $tipos
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function add(Request $request, Response $response, Factory $factory): Response {
|
||||
$input = json_decode($request->getBody());
|
||||
$results = [];
|
||||
if (is_array($input)) {
|
||||
foreach ($input as $in) {
|
||||
$tipo = TipoCategoria::add($factory, $in);
|
||||
$results []= ['tipo' => $tipo?->toArray(), 'agregado' => $tipo?->save()];
|
||||
}
|
||||
} else {
|
||||
$tipo = TipoCategoria::add($factory, $input);
|
||||
$results []= ['tipo' => $tipo?->toArray(), 'agregado' => $tipo?->save()];
|
||||
}
|
||||
$output = [
|
||||
'input' => $input,
|
||||
'tipos' => $results
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function edit(Request $request, Response $response, Factory $factory, $tipo_id): Response {
|
||||
$tipo = $factory->find(TipoCategoria::class)->one($tipo_id);
|
||||
$output = [
|
||||
'input' => $tipo_id,
|
||||
'old' => $tipo->toArray()
|
||||
];
|
||||
$input = json_decode($request->getBody());
|
||||
$tipo->edit($input);
|
||||
$output['tipo'] = $tipo->toArray();
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function delete(Request $request, Response $response, Factory $factory, $tipo_id): Response {
|
||||
$tipo = $factory->find(TipoCategoria::class)->one($tipo_id);
|
||||
$output = [
|
||||
'input' => $tipo_id,
|
||||
'tipo' => $tipo->toArray(),
|
||||
'eliminado' => $tipo->delete()
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function categorias(Request $request, Response $response, Factory $factory, Service $service, $tipo_id): Response {
|
||||
$tipo = $factory->find(TipoCategoria::class)->one($tipo_id);
|
||||
$categorias = null;
|
||||
if ($tipo != null) {
|
||||
$categorias = $tipo->categorias();
|
||||
if ($categorias !== null) {
|
||||
array_walk($categorias, function(&$item) use ($service) {
|
||||
$arr = $item->toArray($service);
|
||||
$maps = ['activo', 'pasivo', 'ganancia', 'perdida'];
|
||||
foreach ($maps as $m) {
|
||||
$p = $m . 's';
|
||||
$t = ucfirst($m);
|
||||
$cuentas = $item->getCuentasOf($t);
|
||||
if ($cuentas === false or $cuentas === null) {
|
||||
$arr[$p] = 0;
|
||||
continue;
|
||||
}
|
||||
$arr[$p] = array_reduce($cuentas, function($sum, $item) use($service) {
|
||||
return $sum + $item->saldo($service, true);
|
||||
});
|
||||
}
|
||||
$item = $arr;
|
||||
});
|
||||
}
|
||||
}
|
||||
$output = [
|
||||
'input' => $tipo_id,
|
||||
'tipo' => $tipo?->toArray(),
|
||||
'categorias' => $categorias
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function balance(Request $request, Response $response, Factory $factory, Service $service): Response {
|
||||
$tipos = $factory->find(TipoCategoria::class)->many();
|
||||
$balance = array_reduce($tipos, function($sum, $item) use ($service) {
|
||||
$maps = ['activo', 'pasivo', 'ganancia', 'perdida'];
|
||||
foreach ($maps as $m) {
|
||||
$p = $m . 's';
|
||||
$t = ucfirst($m);
|
||||
if (!isset($sum[$p])) {
|
||||
$sum[$p] = 0;
|
||||
}
|
||||
$cuentas = $item->getCuentasOf($t);
|
||||
if ($cuentas === false or $cuentas === null) {
|
||||
continue;
|
||||
}
|
||||
$sum[$p] += array_reduce($cuentas, function($sum, $item) use($service) {
|
||||
return $sum + $item->saldo($service, true);
|
||||
});
|
||||
}
|
||||
return $sum;
|
||||
});
|
||||
return $this->withJson($response, $balance);
|
||||
}
|
||||
}
|
71
api/common/Controller/TiposCuentas.php
Normal file
71
api/common/Controller/TiposCuentas.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Controller;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use ProVM\Common\Define\Controller\Json;
|
||||
use ProVM\Common\Factory\Model as Factory;
|
||||
use Contabilidad\TipoCuenta;
|
||||
|
||||
class TiposCuentas {
|
||||
use Json;
|
||||
|
||||
public function __invoke(Request $request, Response $response, Factory $factory): Response {
|
||||
$tipos = $factory->find(TipoCuenta::class)->array();
|
||||
if ($tipos) {
|
||||
usort($tipos, function($a, $b) {
|
||||
return strcmp($a['descripcion'], $b['descripcion']);
|
||||
});
|
||||
}
|
||||
$output = [
|
||||
'tipos' => $tipos
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function show(Request $request, Response $response, Factory $factory, $tipo_id): Response {
|
||||
$tipo = $factory->find(TipoCuenta::class)->one($tipo_id);
|
||||
$output = [
|
||||
'input' => $tipo_id,
|
||||
'tipo' => $tipo?->toArray()
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function add(Request $request, Response $response, Factory $factory): Response {
|
||||
$input = json_decode($request->getBody());
|
||||
$results = [];
|
||||
if (is_array($input)) {
|
||||
foreach ($input as $in) {
|
||||
$tipo = TipoCuenta::add($factory, $in);
|
||||
$results []= ['tipo' => $tipo?->toArray(), 'agregado' => $tipo?->save()];
|
||||
}
|
||||
} else {
|
||||
$tipo = TipoCuenta::add($factory, $input);
|
||||
$results []= ['tipo' => $tipo?->toArray(), 'agregado' => $tipo?->save()];
|
||||
}
|
||||
$output = [
|
||||
'input' => $input,
|
||||
'tipos' => $results
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function edit(Request $request, Response $response, Factory $factory, $tipo_id): Response {
|
||||
$tipo = $factory->find(TipoCuenta::class)->one($tipo_id);
|
||||
$output = [
|
||||
'input' => $tipo_id,
|
||||
'old' => $tipo->toArray()
|
||||
];
|
||||
$input = json_decode($request->getBody());
|
||||
$tipo->edit($input);
|
||||
$output['tipo'] = $tipo->toArray();
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function delete(Request $request, Response $response, Factory $factory, $tipo_id): Response {
|
||||
$tipo = $factory->find(TipoCuenta::class)->one($tipo_id);
|
||||
$output = [
|
||||
'input' => $tipo_id,
|
||||
'tipo' => $tipo->toArray(),
|
||||
'eliminado' => $tipo->delete()
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
}
|
29
api/common/Middleware/Auth.php
Normal file
29
api/common/Middleware/Auth.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Middleware;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface as Handler;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ResponseFactoryInterface as Factory;
|
||||
use Contabilidad\Common\Service\Auth as Service;
|
||||
|
||||
class Auth {
|
||||
protected Factory $factory;
|
||||
protected Service $service;
|
||||
public function __construct(Factory $factory, Service $service) {
|
||||
$this->factory = $factory;
|
||||
$this->service = $service;
|
||||
}
|
||||
public function __invoke(Request $request, Handler $handler): Response {
|
||||
if ($request->getMethod() == 'OPTIONS') {
|
||||
return $handler->handle($request);
|
||||
}
|
||||
if (!$this->service->isValid($request)) {
|
||||
$response = $this->factory->createResponse(401);
|
||||
$response->getBody()->write(json_encode(['message' => 'Invalid API KEY.']));
|
||||
return $response
|
||||
->withHeader('Content-Type', 'application/json');
|
||||
}
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
49
api/common/Service/Auth.php
Normal file
49
api/common/Service/Auth.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Service;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
|
||||
class Auth {
|
||||
protected string $key;
|
||||
public function __construct(string $api_key) {
|
||||
$this->key = $api_key;
|
||||
}
|
||||
public function isValid(Request $request): bool {
|
||||
if ($request->hasHeader('Authorization')) {
|
||||
$sent_key = $this->getAuthKey($request->getHeader('Authorization'));
|
||||
return $this->key == $sent_key;
|
||||
}
|
||||
if (isset($request->getParsedBody()['api_key'])) {
|
||||
$sent_key = $request->getParsedBody()['api_key'];
|
||||
return $this->key == $sent_key;
|
||||
}
|
||||
$post = $request->getParsedBody() ?? json_decode($request->getBody());
|
||||
$sent_key = $this->getArrayKey($post);
|
||||
if ($sent_key !== null) {
|
||||
return $this->key == $sent_key;
|
||||
}
|
||||
$sent_key = $this->getArrayKey($request->getQueryParams());
|
||||
return $this->key == $sent_key;
|
||||
}
|
||||
protected function getAuthKey($auth) {
|
||||
if (is_array($auth)) {
|
||||
$auth = $auth[0];
|
||||
}
|
||||
if (str_contains($auth, 'Bearer')) {
|
||||
$auth = explode(' ', $auth)[1];
|
||||
}
|
||||
return $auth;
|
||||
}
|
||||
protected function getArrayKey($array) {
|
||||
$posible_keys = [
|
||||
'API_KEY',
|
||||
'api_key',
|
||||
];
|
||||
foreach ($posible_keys as $key) {
|
||||
if (isset($array[$key])) {
|
||||
return $array[$key];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
37
api/common/Service/CsvHandler.php
Normal file
37
api/common/Service/CsvHandler.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Service;
|
||||
|
||||
use Contabilidad\Common\Concept\DocumentHandler;
|
||||
|
||||
class CsvHandler extends DocumentHandler {
|
||||
public function load(): ?array {
|
||||
$folder = $this->folder;
|
||||
$files = new \DirectoryIterator($folder);
|
||||
$output = [];
|
||||
foreach ($files as $file) {
|
||||
if ($file->isDir() or $file->getExtension() != 'csv') {
|
||||
continue;
|
||||
}
|
||||
$bank = 'unknown';
|
||||
$text = trim(file_get_contents($file->getRealPath()));
|
||||
if (str_contains($text, 'SCOTIABANK')) {
|
||||
$bank = 'Scotiabank';
|
||||
}
|
||||
if (str_contains($text, 'BICE')) {
|
||||
$bank = 'BICE';
|
||||
}
|
||||
$data = explode(PHP_EOL, $text);
|
||||
array_walk($data, function(&$item) {
|
||||
$item = trim($item, '; ');
|
||||
if (str_contains($item, ';') !== false) {
|
||||
$item = explode(';', $item);
|
||||
}
|
||||
});
|
||||
$output []= ['bank' => $bank, 'filename' => $file->getBasename(), 'data' => $data];
|
||||
}
|
||||
return $this->build($output);
|
||||
}
|
||||
protected function build(array $data): ?array {
|
||||
return $data;
|
||||
}
|
||||
}
|
16
api/common/Service/DocumentHandler.php
Normal file
16
api/common/Service/DocumentHandler.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Service;
|
||||
|
||||
class DocumentHandler {
|
||||
protected array $handlers;
|
||||
public function __construct(array $handlers) {
|
||||
$this->handlers = $handlers;
|
||||
}
|
||||
public function handle(): array {
|
||||
$output = [];
|
||||
foreach ($this->handlers as $handler) {
|
||||
$output = array_merge($output, $handler->load());
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
}
|
@ -1,15 +1,15 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Service;
|
||||
|
||||
use Contabilidad\Common\Concept\DocumentHandler;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
class PdfHandler {
|
||||
class PdfHandler extends DocumentHandler {
|
||||
protected Client $client;
|
||||
protected string $folder;
|
||||
protected string $url;
|
||||
public function __construct(Client $client, string $pdf_folder, string $url) {
|
||||
parent::__construct($pdf_folder);
|
||||
$this->client = $client;
|
||||
$this->folder = $pdf_folder;
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
@ -25,6 +25,51 @@ class PdfHandler {
|
||||
}
|
||||
$response = $this->client->post($this->url, ['json' => ['files' => $output]]);
|
||||
$output = json_decode($response->getBody());
|
||||
return $output;
|
||||
return $this->build($output);
|
||||
}
|
||||
protected function build(array $data): ?array {
|
||||
foreach ($data as &$file) {
|
||||
$i = $this->findStartRow($file->text);
|
||||
if ($i === -1) {
|
||||
continue;
|
||||
}
|
||||
$e = $this->findEndRow($file->text, $i);
|
||||
if ($e == $i) {
|
||||
continue;
|
||||
}
|
||||
$file->data = array_filter($file->text, function($key) use ($i, $e) {
|
||||
return ($key >= $i) and ($key <= $e);
|
||||
}, ARRAY_FILTER_USE_KEY);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
protected function findStartRow(array $data): int {
|
||||
foreach ($data as $i => $row) {
|
||||
if (!is_array($row)) {
|
||||
continue;
|
||||
}
|
||||
$maybe = false;
|
||||
foreach ($row as $cell) {
|
||||
if (str_contains($cell, '/')) {
|
||||
$maybe = true;
|
||||
}
|
||||
if ($maybe and str_contains($cell, '$')) {
|
||||
return $i - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
protected function findEndRow(array $data, int $start): int {
|
||||
$l = count($data[$start]);
|
||||
for ($i = $start; $i < count($data); $i ++) {
|
||||
if (!is_array($data[$i])) {
|
||||
return $i - 1;
|
||||
}
|
||||
if (count($data[$i]) != $l) {
|
||||
return $i - 1;
|
||||
}
|
||||
}
|
||||
return $start;
|
||||
}
|
||||
}
|
76
api/common/Service/TiposCambios.php
Normal file
76
api/common/Service/TiposCambios.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Service;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use ProVM\Common\Factory\Model as Factory;
|
||||
use Contabilidad\Moneda;
|
||||
use Contabilidad\TipoCambio;
|
||||
|
||||
class TiposCambios {
|
||||
protected $client;
|
||||
protected $factory;
|
||||
protected $base_url;
|
||||
protected $key;
|
||||
public function __construct(Client $client, Factory $factory, $api_url, $api_key) {
|
||||
$this->client = $client;
|
||||
$this->factory = $factory;
|
||||
$this->base_url = $api_url;
|
||||
$this->key = $api_key;
|
||||
}
|
||||
public function get(string $fecha, int $moneda_id) {
|
||||
$fecha = Carbon::parse($fecha);
|
||||
$moneda = $this->factory->find(Moneda::class)->one($moneda_id);
|
||||
if ($moneda->codigo == 'USD') {
|
||||
if ($fecha->weekday() == 0) {
|
||||
$fecha = $fecha->subWeek()->weekday(5);
|
||||
}
|
||||
if ($fecha->weekday() == 6) {
|
||||
$fecha = $fecha->weekday(5);
|
||||
}
|
||||
}
|
||||
$cambio = $moneda->cambio($fecha);
|
||||
if ($cambio) {
|
||||
if ($cambio->desde()->id != $moneda->id) {
|
||||
return 1 / $cambio->valor;
|
||||
}
|
||||
return $cambio->valor;
|
||||
}
|
||||
$data = [
|
||||
'fecha' => $fecha->format('Y-m-d'),
|
||||
'desde' => $moneda->codigo
|
||||
];
|
||||
$headers = [
|
||||
'Authorization' => 'Bearer ' . $this->key
|
||||
];
|
||||
$url = implode('/', [
|
||||
$this->base_url,
|
||||
'cambio',
|
||||
'get'
|
||||
]);
|
||||
try {
|
||||
$response = $this->client->request('POST', $url, ['json' => $data, 'headers' => $headers]);
|
||||
} catch (ConnectException | RequestException $e) {
|
||||
error_log($e);
|
||||
return null;
|
||||
}
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
return null;
|
||||
}
|
||||
$result = json_decode($response->getBody());
|
||||
$valor = $result->serie[0]->valor;
|
||||
$data = [
|
||||
'fecha' => $fecha->format('Y-m-d H:i:s'),
|
||||
'desde_id' => $moneda->id,
|
||||
'hasta_id' => 1,
|
||||
'valor' => $valor
|
||||
];
|
||||
$tipo = TipoCambio::add($this->factory, $data);
|
||||
if ($tipo !== false and $tipo->is_new()) {
|
||||
$tipo->save();
|
||||
}
|
||||
return $valor;
|
||||
}
|
||||
}
|
60
api/common/Service/XlsHandler.php
Normal file
60
api/common/Service/XlsHandler.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Service;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing;
|
||||
use thiagoalessio\TesseractOCR\TesseractOCR;
|
||||
use Contabilidad\Common\Concept\DocumentHandler;
|
||||
|
||||
class XlsHandler extends DocumentHandler {
|
||||
public function load(): ?array {
|
||||
$folder = $this->folder;
|
||||
$files = new \DirectoryIterator($folder);
|
||||
$output = [];
|
||||
foreach ($files as $file) {
|
||||
if ($file->isDir() or $file->getExtension() != 'xls') {
|
||||
continue;
|
||||
}
|
||||
$reader = IOFactory::createReader(ucfirst($file->getExtension()));
|
||||
$xls = $reader->load($file->getRealPath());
|
||||
$data = [];
|
||||
$bank = 'unknown';
|
||||
for ($s = 0; $s < $xls->getSheetCount(); $s ++) {
|
||||
$sheet = $xls->getSheet($s);
|
||||
foreach ($sheet->getRowIterator() as $row) {
|
||||
$r = [];
|
||||
foreach ($row->getCellIterator() as $cell) {
|
||||
$r []= $cell->getValue();
|
||||
}
|
||||
$data []= $r;
|
||||
}
|
||||
foreach ($sheet->getDrawingCollection() as $drawing) {
|
||||
if ($drawing instanceof MemoryDrawing) {
|
||||
ob_start();
|
||||
call_user_func(
|
||||
$drawing->getRenderingFunction(),
|
||||
$drawing->getImageResource()
|
||||
);
|
||||
$imageContents = ob_get_contents();
|
||||
$size = ob_get_length();
|
||||
ob_end_clean();
|
||||
$ocr = new TesseractOCR();
|
||||
$ocr->imageData($imageContents, $size);
|
||||
$image = $ocr->run();
|
||||
if (str_contains($image, 'BICE')) {
|
||||
$bank = 'BICE';
|
||||
}
|
||||
if (str_contains($image, 'Scotiabank')) {
|
||||
$bank = 'Scotiabank';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$output []= ['bank' => $bank, 'filename' => $file->getBasename(), 'data' => $data];
|
||||
}
|
||||
return $this->build($output);
|
||||
}
|
||||
protected function build(array $data): ?array {
|
||||
return $data;
|
||||
}
|
||||
}
|
@ -14,7 +14,9 @@
|
||||
"robmorgan/phinx": "^0.12.9",
|
||||
"odan/phinx-migrations-generator": "^5.4",
|
||||
"martin-mikac/csv-to-phinx-seeder": "^1.6",
|
||||
"guzzlehttp/guzzle": "^7.4"
|
||||
"guzzlehttp/guzzle": "^7.4",
|
||||
"phpoffice/phpspreadsheet": "^1.19",
|
||||
"thiagoalessio/tesseract_ocr": "^2.12"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5",
|
||||
|
@ -20,6 +20,7 @@ final class TipoCuenta extends AbstractMigration
|
||||
{
|
||||
$this->table('tipos_cuenta')
|
||||
->addColumn('descripcion', 'string')
|
||||
->addColumn('color', 'string', ['length' => 6])
|
||||
->create();
|
||||
}
|
||||
}
|
||||
|
29
api/db/migrations/20211204205950_moneda.php
Normal file
29
api/db/migrations/20211204205950_moneda.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class Moneda extends AbstractMigration
|
||||
{
|
||||
/**
|
||||
* Change Method.
|
||||
*
|
||||
* Write your reversible migrations using this method.
|
||||
*
|
||||
* More information on writing migrations is available here:
|
||||
* https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
|
||||
*
|
||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||
* with the Table class.
|
||||
*/
|
||||
public function change(): void
|
||||
{
|
||||
$this->table('monedas')
|
||||
->addColumn('denominacion', 'string')
|
||||
->addColumn('codigo', 'string', ['length' => 3])
|
||||
->addColumn('prefijo', 'string', ['default' => ''])
|
||||
->addColumn('sufijo', 'string', ['default' => ''])
|
||||
->addColumn('decimales', 'integer', ['default' => 0])
|
||||
->create();
|
||||
}
|
||||
}
|
26
api/db/migrations/20211204210207_cuenta_moneda.php
Normal file
26
api/db/migrations/20211204210207_cuenta_moneda.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class CuentaMoneda extends AbstractMigration
|
||||
{
|
||||
/**
|
||||
* Change Method.
|
||||
*
|
||||
* Write your reversible migrations using this method.
|
||||
*
|
||||
* More information on writing migrations is available here:
|
||||
* https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
|
||||
*
|
||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||
* with the Table class.
|
||||
*/
|
||||
public function change(): void
|
||||
{
|
||||
$this->table('cuentas')
|
||||
->addColumn('moneda_id', 'integer')
|
||||
->addForeignKey('moneda_id', 'monedas')
|
||||
->update();
|
||||
}
|
||||
}
|
30
api/db/migrations/20211205002439_tipo_cambio.php
Normal file
30
api/db/migrations/20211205002439_tipo_cambio.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class TipoCambio extends AbstractMigration
|
||||
{
|
||||
/**
|
||||
* Change Method.
|
||||
*
|
||||
* Write your reversible migrations using this method.
|
||||
*
|
||||
* More information on writing migrations is available here:
|
||||
* https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
|
||||
*
|
||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||
* with the Table class.
|
||||
*/
|
||||
public function change(): void
|
||||
{
|
||||
$this->table('tipos_cambio')
|
||||
->addColumn('fecha', 'datetime')
|
||||
->addColumn('desde_id', 'integer')
|
||||
->addForeignKey('desde_id', 'monedas')
|
||||
->addColumn('hasta_id', 'integer')
|
||||
->addForeignKey('hasta_id', 'monedas')
|
||||
->addColumn('valor', 'double')
|
||||
->create();
|
||||
}
|
||||
}
|
41
api/db/seeds/Moneda.php
Normal file
41
api/db/seeds/Moneda.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
|
||||
use Phinx\Seed\AbstractSeed;
|
||||
|
||||
class Moneda extends AbstractSeed
|
||||
{
|
||||
/**
|
||||
* Run Method.
|
||||
*
|
||||
* Write your database seeder using this method.
|
||||
*
|
||||
* More information on writing seeders is available here:
|
||||
* https://book.cakephp.org/phinx/0/en/seeding.html
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$data = [
|
||||
[
|
||||
'denominacion' => 'Pesos Chilenos',
|
||||
'codigo' => 'CLP',
|
||||
'prefijo' => '$ '
|
||||
],
|
||||
[
|
||||
'denominacion' => 'Dólar',
|
||||
'codigo' => 'USD',
|
||||
'prefijo' => 'US$ ',
|
||||
'decimales' => 2
|
||||
],
|
||||
[
|
||||
'denominacion' => 'Unidad de Fomento',
|
||||
'codigo' => 'CLF',
|
||||
'sufijo' => ' UF',
|
||||
'decimales' => 2
|
||||
]
|
||||
];
|
||||
$this->table('monedas')
|
||||
->insert($data)
|
||||
->saveData();
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Base;
|
||||
|
||||
$app->get('/key/generate[/]', [Base::class, 'generate_key']);
|
||||
$app->get('/balance[/]', [Contabilidad\Common\Controller\TiposCategorias::class, 'balance']);
|
||||
$app->get('/', Base::class);
|
||||
|
12
api/resources/routes/monedas.php
Normal file
12
api/resources/routes/monedas.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Monedas;
|
||||
|
||||
$app->group('/monedas', function($app) {
|
||||
$app->post('/add[/]', [Monedas::class, 'add']);
|
||||
$app->get('[/]', Monedas::class);
|
||||
});
|
||||
$app->group('/moneda/{moneda_id}', function($app) {
|
||||
$app->put('/edit', [Monedas::class, 'edit']);
|
||||
$app->delete('/delete', [Monedas::class, 'delete']);
|
||||
$app->get('[/]', [Monedas::class, 'show']);
|
||||
});
|
16
api/resources/routes/tipos.php
Normal file
16
api/resources/routes/tipos.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
$folder = implode(DIRECTORY_SEPARATOR, [
|
||||
__DIR__,
|
||||
'tipos'
|
||||
]);
|
||||
if (file_exists($folder)) {
|
||||
$app->group('/tipos', function($app) use ($folder) {
|
||||
$files = new DirectoryIterator($folder);
|
||||
foreach ($files as $file) {
|
||||
if ($file->isDir() or $file->getExtension() != 'php') {
|
||||
continue;
|
||||
}
|
||||
include_once $file->getRealPath();
|
||||
}
|
||||
});
|
||||
}
|
13
api/resources/routes/tipos/cambios.php
Normal file
13
api/resources/routes/tipos/cambios.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\TiposCambios;
|
||||
|
||||
$app->group('/cambios', function($app) {
|
||||
$app->post('/obtener[/]', [TiposCambios::class, 'obtain']);
|
||||
$app->post('/add[/]', [TiposCambios::class, 'add']);
|
||||
$app->get('[/]', TiposCambios::class);
|
||||
});
|
||||
$app->group('/cambio/{tipo_id}', function($app) {
|
||||
$app->put('/edit[/]', [TiposCambios::class, 'edit']);
|
||||
$app->delete('/delete[/]', [TiposCambios::class, 'delete']);
|
||||
$app->get('[/]', [TiposCambios::class, 'show']);
|
||||
});
|
13
api/resources/routes/tipos/categorias.php
Normal file
13
api/resources/routes/tipos/categorias.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\TiposCategorias;
|
||||
|
||||
$app->group('/categorias', function($app) {
|
||||
$app->post('/add[/]', [TiposCategorias::class, 'add']);
|
||||
$app->get('[/]', TiposCategorias::class);
|
||||
});
|
||||
$app->group('/categoria/{tipo_id}', function($app) {
|
||||
$app->get('/categorias', [TiposCategorias::class, 'categorias']);
|
||||
$app->put('/edit', [TiposCategorias::class, 'edit']);
|
||||
$app->delete('/delete', [TiposCategorias::class, 'delete']);
|
||||
$app->get('[/]', [TiposCategorias::class, 'show']);
|
||||
});
|
12
api/resources/routes/tipos/cuentas.php
Normal file
12
api/resources/routes/tipos/cuentas.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\TiposCuentas;
|
||||
|
||||
$app->group('/cuentas', function($app) {
|
||||
$app->post('/add[/]', [TiposCuentas::class, 'add']);
|
||||
$app->get('[/]', TiposCuentas::class);
|
||||
});
|
||||
$app->group('/cuenta/{tipo_id}', function($app) {
|
||||
$app->put('/edit', [TiposCuentas::class, 'edit']);
|
||||
$app->delete('/delete', [TiposCuentas::class, 'delete']);
|
||||
$app->get('[/]', [TiposCuentas::class, 'show']);
|
||||
});
|
@ -31,7 +31,7 @@ $app->addRoutingMiddleware();
|
||||
$app->add(new WhoopsMiddleware());
|
||||
|
||||
|
||||
$folder = 'middlewares';
|
||||
$folder = implode(DIRECTORY_SEPARATOR, [__DIR__, 'middlewares']);
|
||||
if (file_exists($folder)) {
|
||||
$files = new DirectoryIterator($folder);
|
||||
foreach ($files as $file) {
|
||||
|
4
api/setup/middlewares/01_auth.php
Normal file
4
api/setup/middlewares/01_auth.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Middleware\Auth;
|
||||
|
||||
$app->add($app->getContainer()->get(Auth::class));
|
@ -1,4 +1,7 @@
|
||||
<?php
|
||||
return [
|
||||
'debug' => $_ENV['DEBUG'] ?? false
|
||||
'debug' => $_ENV['DEBUG'] ?? false,
|
||||
'api_key' => $_ENV['API_KEY'],
|
||||
'python_api' => $_ENV['PYTHON_API'] ?? 'http://python:5000',
|
||||
'python_key' => $_ENV['PYTHON_KEY']
|
||||
];
|
||||
|
@ -26,6 +26,14 @@ return [
|
||||
$arr['uploads'],
|
||||
'pdfs'
|
||||
]);
|
||||
$arr['csvs'] = implode(DIRECTORY_SEPARATOR, [
|
||||
$arr['uploads'],
|
||||
'csvs'
|
||||
]);
|
||||
$arr['xlss'] = implode(DIRECTORY_SEPARATOR, [
|
||||
$arr['uploads'],
|
||||
'xlss'
|
||||
]);
|
||||
return (object) $arr;
|
||||
},
|
||||
'urls' => function(Container $c) {
|
||||
|
@ -5,11 +5,42 @@ return [
|
||||
GuzzleHttp\Client::class => function(Container $c) {
|
||||
return new GuzzleHttp\Client();
|
||||
},
|
||||
Contabilidad\Common\Service\Auth::class => function(Container $c) {
|
||||
return new Contabilidad\Common\Service\Auth($c->get('api_key'));
|
||||
},
|
||||
Contabilidad\Common\Middleware\Auth::class => function(Container $c) {
|
||||
return new Contabilidad\Common\Middleware\Auth(
|
||||
$c->get(Nyholm\Psr7\Factory\Psr17Factory::class),
|
||||
$c->get(Contabilidad\Common\Service\Auth::class)
|
||||
);
|
||||
},
|
||||
Contabilidad\Common\Service\PdfHandler::class => function(Container $c) {
|
||||
return new Contabilidad\Common\Service\PdfHandler($c->get(GuzzleHttp\Client::class), $c->get('folders')->pdfs, implode('/', [
|
||||
$c->get('urls')->python,
|
||||
'pdf',
|
||||
'parse'
|
||||
]));
|
||||
}
|
||||
},
|
||||
Contabilidad\Common\Service\CsvHandler::class => function(Container $c) {
|
||||
return new Contabilidad\Common\Service\CsvHandler($c->get('folders')->csvs);
|
||||
},
|
||||
Contabilidad\Common\Service\XlsHandler::class => function(Container $c) {
|
||||
return new Contabilidad\Common\Service\XlsHandler($c->get('folders')->xlss);
|
||||
},
|
||||
Contabilidad\Common\Service\DocumentHandler::class => function(Container $c) {
|
||||
$handlers = [
|
||||
$c->get(Contabilidad\Common\Service\XlsHandler::class),
|
||||
$c->get(Contabilidad\Common\Service\CsvHandler::class),
|
||||
$c->get(Contabilidad\Common\Service\PdfHandler::class)
|
||||
];
|
||||
return new Contabilidad\Common\Service\DocumentHandler($handlers);
|
||||
},
|
||||
Contabilidad\Common\Service\TiposCambios::class => function(Container $c) {
|
||||
return new Contabilidad\Common\Service\TiposCambios(
|
||||
$c->get(GuzzleHttp\Client::class),
|
||||
$c->get(ProVM\Common\Factory\Model::class),
|
||||
$c->get('python_api'),
|
||||
$c->get('python_key')
|
||||
);
|
||||
}
|
||||
];
|
||||
|
@ -1,7 +1,9 @@
|
||||
<?php
|
||||
namespace Contabilidad;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use ProVM\Common\Alias\Model;
|
||||
use Contabilidad\Common\Service\TiposCambios as Service;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
@ -10,7 +12,7 @@ use ProVM\Common\Alias\Model;
|
||||
*/
|
||||
class Categoria extends Model {
|
||||
public static $_table = 'categorias';
|
||||
protected static $fields = ['nombre'];
|
||||
protected static $fields = ['nombre', 'tipo_id'];
|
||||
|
||||
protected $cuentas;
|
||||
public function cuentas() {
|
||||
@ -27,24 +29,64 @@ class Categoria extends Model {
|
||||
return $this->tipo;
|
||||
}
|
||||
|
||||
public function getCuentasOf($tipo) {
|
||||
return $this->factory->find(Cuenta::class)
|
||||
->select([['cuentas', '*']])
|
||||
->join([
|
||||
['tipos_cuenta', 'tipos_cuenta.id', 'cuentas.tipo_id']
|
||||
])
|
||||
->where([
|
||||
['tipos_cuenta.descripcion', $tipo],
|
||||
['cuentas.categoria_id', $this->id]
|
||||
])
|
||||
->many();
|
||||
}
|
||||
protected $activos;
|
||||
public function activos() {
|
||||
if ($this->activos === null) {
|
||||
$this->activos = $this->getCuentasOf('Activo');
|
||||
}
|
||||
return $this->activos();
|
||||
}
|
||||
protected $pasivos;
|
||||
public function pasivos() {
|
||||
if ($this->pasivos === null) {
|
||||
$this->activos = $this->getCuentasOf('Pasivo');
|
||||
}
|
||||
return $this->pasivos;
|
||||
}
|
||||
protected $ganancias;
|
||||
public function ganancias() {
|
||||
if ($this->ganancias === null) {
|
||||
$this->ganancias = $this->getCuentasOf('Ganancia');
|
||||
}
|
||||
return $this->ganancias;
|
||||
}
|
||||
protected $perdidas;
|
||||
public function perdidas() {
|
||||
if ($this->perdidas === null) {
|
||||
$this->perdidas = $this->getCuentasOf('Perdida');
|
||||
}
|
||||
return $this->perdidas;
|
||||
}
|
||||
|
||||
protected $saldo;
|
||||
public function saldo() {
|
||||
public function saldo(Service $service = null) {
|
||||
if ($this->saldo === null) {
|
||||
$this->saldo = 0;
|
||||
if ($this->cuentas() !== null) {
|
||||
$this->saldo = array_reduce($this->cuentas(), function($sum, $item) {
|
||||
return $sum + $item->saldo();
|
||||
});
|
||||
$sum = 0;
|
||||
$debitos = ['Activo', 'Perdida'];
|
||||
foreach ($this->cuentas() as $cuenta) {
|
||||
if (array_search($cuenta->tipo()->descripcion, $debitos) !== false) {
|
||||
$sum -= $cuenta->saldo($service, true);
|
||||
continue;
|
||||
}
|
||||
$sum += $cuenta->saldo($service, true);
|
||||
}
|
||||
$this->saldo = $sum;
|
||||
}
|
||||
}
|
||||
return $this->saldo;
|
||||
}
|
||||
|
||||
public function toArray(): array {
|
||||
$arr = parent::toArray();
|
||||
$arr['tipo'] = $this->tipo()->toArray();
|
||||
$arr['saldo'] = $this->saldo();
|
||||
$arr['saldoFormateado'] = '$' . number_format($this->saldo(), 0, ',', '.');
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,20 @@
|
||||
<?php
|
||||
namespace Contabilidad;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use ProVM\Common\Alias\Model;
|
||||
use Contabilidad\Common\Service\TiposCambios as Service;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $nombre
|
||||
* @property Categoria $categoria_id
|
||||
* @property TipoCuenta $tipo_id
|
||||
* @property Moneda $moneda_id
|
||||
*/
|
||||
class Cuenta extends Model {
|
||||
public static $_table = 'cuentas';
|
||||
protected static $fields = ['nombre', 'categoria_id', 'tipo_id'];
|
||||
protected static $fields = ['nombre', 'categoria_id', 'tipo_id', 'moneda_id'];
|
||||
|
||||
protected $categoria;
|
||||
public function categoria() {
|
||||
@ -20,25 +23,32 @@ class Cuenta extends Model {
|
||||
}
|
||||
return $this->categoria;
|
||||
}
|
||||
protected $cuenta;
|
||||
public function cuenta() {
|
||||
if ($this->cuenta === null) {
|
||||
$this->cuenta = $this->childOf(TipoCuenta::class, [Model::SELF_KEY => 'tipo_id']);
|
||||
protected $tipo;
|
||||
public function tipo() {
|
||||
if ($this->tipo === null) {
|
||||
$this->tipo = $this->childOf(TipoCuenta::class, [Model::SELF_KEY => 'tipo_id']);
|
||||
}
|
||||
return $this->cuenta;
|
||||
return $this->tipo;
|
||||
}
|
||||
protected $moneda;
|
||||
public function moneda() {
|
||||
if ($this->moneda === null) {
|
||||
$this->moneda = $this->childOf(Moneda::class, [Model::SELF_KEY => 'moneda_id']);
|
||||
}
|
||||
return $this->moneda;
|
||||
}
|
||||
|
||||
protected $cargos;
|
||||
public function cargos() {
|
||||
if ($this->cargos === null) {
|
||||
$this->cargos = $this->parentOf(Transaccion::class, [Model::CHILD_KEY => 'hasta_id']);
|
||||
$this->cargos = $this->parentOf(Transaccion::class, [Model::CHILD_KEY => 'credito_id']);
|
||||
}
|
||||
return $this->cargos;
|
||||
}
|
||||
protected $abonos;
|
||||
public function abonos() {
|
||||
if ($this->abonos === null) {
|
||||
$this->abonos = $this->parentOf(Transaccion::class, [Model::CHILD_KEY => 'desde_id']);
|
||||
$this->abonos = $this->parentOf(Transaccion::class, [Model::CHILD_KEY => 'debito_id']);
|
||||
}
|
||||
return $this->abonos;
|
||||
}
|
||||
@ -46,7 +56,7 @@ class Cuenta extends Model {
|
||||
public function transacciones($limit = null, $start = 0) {
|
||||
if ($this->transacciones === null) {
|
||||
$transacciones = Model::factory(Transaccion::class)
|
||||
->join('cuentas', 'cuentas.id = transacciones.desde_id OR cuentas.id = transacciones.hasta_id')
|
||||
->join('cuentas', 'cuentas.id = transacciones.debito_id OR cuentas.id = transacciones.credito_id')
|
||||
->whereEqual('cuentas.id', $this->id)
|
||||
->orderByAsc('transacciones.fecha');
|
||||
if ($limit !== null) {
|
||||
@ -64,23 +74,40 @@ class Cuenta extends Model {
|
||||
return $this->transacciones;
|
||||
}
|
||||
protected $saldo;
|
||||
public function saldo() {
|
||||
public function saldo(Service $service = null, $in_clp = false) {
|
||||
if ($this->saldo === null) {
|
||||
$this->saldo = 0;
|
||||
if (count($this->transacciones()) > 0) {
|
||||
$this->saldo = array_reduce($this->transacciones(), function($sum, $item) {
|
||||
return $sum + $item->valor;
|
||||
return $sum + $item->valor;
|
||||
});
|
||||
}
|
||||
}
|
||||
if ($in_clp and $this->moneda()->codigo !== 'CLP') {
|
||||
$fecha = Carbon::today();
|
||||
if ($this->moneda()->codigo == 'USD') {
|
||||
$fecha = match ($fecha->weekday()) {
|
||||
0 => $fecha->subWeek()->weekday(5),
|
||||
6 => $fecha->weekday(5),
|
||||
default => $fecha
|
||||
};
|
||||
}
|
||||
$service->get($fecha->format('Y-m-d'), $this->moneda()->id);
|
||||
return $this->moneda()->cambiar($fecha, $this->saldo);
|
||||
}
|
||||
return $this->saldo;
|
||||
}
|
||||
|
||||
public function toArray(): array {
|
||||
public function format($valor) {
|
||||
return $this->moneda()->format($valor);
|
||||
}
|
||||
|
||||
public function toArray(Service $service = null, $in_clp = false): array {
|
||||
$arr = parent::toArray();
|
||||
$arr['categoria'] = $this->categoria()->toArray();
|
||||
$arr['saldo'] = $this->saldo();
|
||||
$arr['saldoFormateado'] = '$' . number_format($this->saldo(), 0, ',', '.');
|
||||
$arr['tipo'] = $this->tipo()->toArray();
|
||||
$arr['moneda'] = $this->moneda()->toArray();
|
||||
$arr['saldo'] = $this->saldo($service, $in_clp);
|
||||
$arr['saldoFormateado'] = $this->format($this->saldo($service, $in_clp));
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
|
46
api/src/Moneda.php
Normal file
46
api/src/Moneda.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
namespace Contabilidad;
|
||||
|
||||
use ProVM\Common\Alias\Model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $denominacion
|
||||
* @property string $codigo
|
||||
* @property string $sufijo
|
||||
* @property string $prefijo
|
||||
* @property int $decimales
|
||||
*/
|
||||
class Moneda extends Model {
|
||||
public static $_table = 'monedas';
|
||||
protected static $fields = ['denominacion', 'codigo'];
|
||||
|
||||
public function format($valor) {
|
||||
return implode('', [
|
||||
$this->prefijo,
|
||||
number_format($valor, $this->decimales, ',', '.'),
|
||||
$this->sufijo
|
||||
]);
|
||||
}
|
||||
public function cambio(\DateTime $fecha) {
|
||||
$cambio = $this->factory->find(TipoCambio::class)
|
||||
->where([['desde_id', $this->id], ['hasta_id', 1], ['fecha', $fecha->format('Y-m-d H:i:s')]])
|
||||
->one();
|
||||
if (!$cambio) {
|
||||
$cambio = $this->factory->find(TipoCambio::class)
|
||||
->where([['hasta_id', $this->id], ['desde_id', 1], ['fecha', $fecha->format('Y-m-d H:i:s')]])
|
||||
->one();
|
||||
}
|
||||
return $cambio;
|
||||
}
|
||||
public function cambiar(\DateTime $fecha, float $valor) {
|
||||
$cambio = $this->cambio($fecha);
|
||||
if (!$cambio) {
|
||||
return $valor;
|
||||
}
|
||||
if ($cambio->desde()->id != $this->id) {
|
||||
return $cambio->transform($valor, TipoCambio::DESDE);
|
||||
}
|
||||
return $cambio->transform($valor);
|
||||
}
|
||||
}
|
50
api/src/TipoCambio.php
Normal file
50
api/src/TipoCambio.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
namespace Contabilidad;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use DateTime;
|
||||
use ProVM\Common\Alias\Model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property DateTime $fecha
|
||||
* @property Moneda $desde_id
|
||||
* @property Moneda $hasta_id
|
||||
* @property float $valor
|
||||
*/
|
||||
class TipoCambio extends Model {
|
||||
const DESDE = -1;
|
||||
const HASTA = 1;
|
||||
|
||||
public static $_table = 'tipos_cambio';
|
||||
protected static $fields = ['fecha', 'valor', 'desde_id', 'hasta_id'];
|
||||
|
||||
protected $desde;
|
||||
public function desde() {
|
||||
if ($this->desde === null) {
|
||||
$this->desde = $this->childOf(Moneda::class, [Model::SELF_KEY => 'desde_id']);
|
||||
}
|
||||
return $this->desde;
|
||||
}
|
||||
protected $hasta;
|
||||
public function hasta() {
|
||||
if ($this->hasta === null) {
|
||||
$this->hasta = $this->childOf(Moneda::class, [Model::SELF_KEY => 'hasta_id']);
|
||||
}
|
||||
return $this->hasta;
|
||||
}
|
||||
public function fecha(DateTime $fecha = null) {
|
||||
if ($fecha === null) {
|
||||
return Carbon::parse($this->fecha);
|
||||
}
|
||||
$this->fecha = $fecha->format('Y-m-d H:i:s');
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function transform(float $valor, int $direction = TipoCambio::HASTA): float {
|
||||
if ($direction == TipoCambio::HASTA) {
|
||||
return $valor * $this->valor;
|
||||
}
|
||||
return $valor / $this->valor;
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
namespace Contabilidad;
|
||||
|
||||
use ProVM\Common\Alias\Model;
|
||||
use Contabilidad\Common\Service\TiposCambios as Service;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
@ -11,4 +12,35 @@ use ProVM\Common\Alias\Model;
|
||||
class TipoCategoria extends Model {
|
||||
public static $_table = 'tipos_categoria';
|
||||
protected static $fields = ['descripcion', 'activo'];
|
||||
|
||||
protected $categorias;
|
||||
public function categorias() {
|
||||
if ($this->categorias === null) {
|
||||
$this->categorias = $this->parentOf(Categoria::class, [Model::CHILD_KEY => 'tipo_id']);
|
||||
}
|
||||
return $this->categorias;
|
||||
}
|
||||
|
||||
public function getCuentasOf($tipo) {
|
||||
return $this->factory->find(Cuenta::class)
|
||||
->select([['cuentas', '*']])
|
||||
->join([
|
||||
['tipos_cuenta', 'tipos_cuenta.id', 'cuentas.tipo_id'],
|
||||
['categorias', 'categorias.id', 'cuentas.categoria_id']
|
||||
])
|
||||
->where([
|
||||
['tipos_cuenta.descripcion', $tipo],
|
||||
['categorias.tipo_id', $this->id]
|
||||
])->many();
|
||||
}
|
||||
|
||||
protected $saldo;
|
||||
public function saldo(Service $service = null) {
|
||||
if ($this->saldo === null) {
|
||||
$this->saldo = array_reduce($this->categorias(), function($sum, $item) use ($service) {
|
||||
return $sum + $item->saldo($service);
|
||||
});
|
||||
}
|
||||
return $this->saldo;
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,9 @@ use ProVM\Common\Alias\Model;
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $descripcion
|
||||
* @property string $color
|
||||
*/
|
||||
class TipoCuenta extends Model {
|
||||
public static $_table = 'tipos_cuenta';
|
||||
protected static $fields = ['descripcion'];
|
||||
}
|
||||
protected static $fields = ['descripcion', 'color'];
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace Contabilidad;
|
||||
|
||||
use DateTime;
|
||||
use Carbon\Carbon;
|
||||
use ProVM\Common\Alias\Model;
|
||||
|
||||
@ -8,7 +9,7 @@ use ProVM\Common\Alias\Model;
|
||||
* @property int $id
|
||||
* @property Cuenta $debito_id
|
||||
* @property Cuenta $credito_id
|
||||
* @property \DateTime $fecha
|
||||
* @property DateTime $fecha
|
||||
* @property string $glosa
|
||||
* @property string $detalle
|
||||
* @property double $valor
|
||||
@ -31,7 +32,7 @@ class Transaccion extends Model {
|
||||
}
|
||||
return $this->credito;
|
||||
}
|
||||
public function fecha(\DateTime $fecha = null) {
|
||||
public function fecha(DateTime $fecha = null) {
|
||||
if ($fecha === null) {
|
||||
return Carbon::parse($this->fecha);
|
||||
}
|
||||
@ -43,7 +44,7 @@ class Transaccion extends Model {
|
||||
$arr['debito'] = $this->debito()->toArray();
|
||||
$arr['credito'] = $this->credito()->toArray();
|
||||
$arr['fechaFormateada'] = $this->fecha()->format('d-m-Y');
|
||||
$arr['valorFormateado'] = '$' . number_format($this->valor, 0, ',', '.');
|
||||
$arr['valorFormateado'] = $this->debito()->moneda()->format($this->valor);
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
|
@ -2,16 +2,23 @@ version: '3'
|
||||
|
||||
services:
|
||||
api:
|
||||
profiles:
|
||||
- api
|
||||
restart: unless-stopped
|
||||
image: php
|
||||
build:
|
||||
context: api
|
||||
env_file: .env
|
||||
env_file:
|
||||
- .env
|
||||
- .api.env
|
||||
- .python.env
|
||||
volumes:
|
||||
- ./api/:/app/
|
||||
- ./api/php.ini:/usr/local/etc/php/conf.d/php.ini
|
||||
- ./logs/api/php/:/var/log/php/
|
||||
api-proxy:
|
||||
profiles:
|
||||
- api
|
||||
restart: unless-stopped
|
||||
image: nginx
|
||||
ports:
|
||||
@ -21,25 +28,37 @@ services:
|
||||
- ./logs/api/:/var/log/nginx/
|
||||
- ./api/:/app/
|
||||
db:
|
||||
profiles:
|
||||
- api
|
||||
restart: unless-stopped
|
||||
image: mariadb
|
||||
env_file: .env
|
||||
volumes:
|
||||
- contabilidad_data:/var/lib/mysql
|
||||
adminer:
|
||||
profiles:
|
||||
- api
|
||||
restart: unless-stopped
|
||||
image: adminer
|
||||
ports:
|
||||
- "9002:8080"
|
||||
|
||||
ui:
|
||||
profiles:
|
||||
- ui
|
||||
restart: unless-stopped
|
||||
image: php-ui
|
||||
env_file:
|
||||
- .api.env
|
||||
build:
|
||||
context: ui
|
||||
volumes:
|
||||
- ./ui/:/app/
|
||||
- ./ui/php.ini:/usr/local/etc/php/conf.d/php.ini
|
||||
- ./logs/ui/php/:/var/log/php/
|
||||
ui-proxy:
|
||||
profiles:
|
||||
- ui
|
||||
restart: unless-stopped
|
||||
image: nginx
|
||||
ports:
|
||||
@ -50,9 +69,15 @@ services:
|
||||
- ./ui/:/app/
|
||||
|
||||
python:
|
||||
profiles:
|
||||
- python
|
||||
restart: unless-stopped
|
||||
build:
|
||||
context: ./python
|
||||
env_file:
|
||||
- .python.env
|
||||
ports:
|
||||
- "9003:5000"
|
||||
volumes:
|
||||
- ./python/src/:/app/src/
|
||||
- ./python/config/:/app/config/
|
||||
|
12
ui/common/Controller/Config.php
Normal file
12
ui/common/Controller/Config.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Controller;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Slim\Views\Blade as View;
|
||||
|
||||
class Config {
|
||||
public function __invoke(Request $request, Response $response, View $view): Response {
|
||||
return $view->render($response, 'config.list');
|
||||
}
|
||||
}
|
@ -9,4 +9,7 @@ class Home {
|
||||
public function __invoke(Request $request, Response $response, View $view): Response {
|
||||
return $view->render($response, 'home');
|
||||
}
|
||||
public function info(Request $request, Response $response, View $view): Response {
|
||||
return $view->render($response, 'info');
|
||||
}
|
||||
}
|
||||
|
12
ui/common/Controller/TiposCategorias.php
Normal file
12
ui/common/Controller/TiposCategorias.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Controller;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Slim\Views\Blade as View;
|
||||
|
||||
class TiposCategorias {
|
||||
public function __invoke(Request $request, Response $response, View $view): Response {
|
||||
return $view->render($response, 'categorias.tipos.list');
|
||||
}
|
||||
}
|
12
ui/common/Controller/TiposCuentas.php
Normal file
12
ui/common/Controller/TiposCuentas.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Controller;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Slim\Views\Blade as View;
|
||||
|
||||
class TiposCuentas {
|
||||
public function __invoke(Request $request, Response $response, View $view): Response {
|
||||
return $view->render($response, 'cuentas.tipos.list');
|
||||
}
|
||||
}
|
4
ui/php.ini
Normal file
4
ui/php.ini
Normal file
@ -0,0 +1,4 @@
|
||||
[PHP]
|
||||
display_errors = E_ALL
|
||||
log_errors = true
|
||||
error_log = /var/log/php/error.log
|
@ -1,28 +1,92 @@
|
||||
class Categoria {
|
||||
constructor({id, nombre, tipo_id, tipo, saldo, saldoFormateado}) {
|
||||
this.id = id
|
||||
this.nombre = nombre
|
||||
this.tipo_id = tipo_id
|
||||
this.tipo = tipo
|
||||
this.modal = null
|
||||
}
|
||||
setModal(modal) {
|
||||
this.modal = modal
|
||||
}
|
||||
draw() {
|
||||
return $('<tr></tr>').append(
|
||||
$('<td></td>').html(this.nombre)
|
||||
).append(
|
||||
$('<td></td>').html(this.tipo.descripcion)
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').append(
|
||||
$('<button></button>').attr('class', 'ui tiny circular icon button').attr('data-id', this.id).append(
|
||||
$('<i></i>').attr('class', 'edit icon')
|
||||
).click((e) => {
|
||||
e.preventDefault()
|
||||
this.edit()
|
||||
return false
|
||||
})
|
||||
).append(
|
||||
$('<button></button>').attr('class', 'ui tiny circular red icon button').attr('data-id', this.id).append(
|
||||
$('<i></i>').attr('class', 'remove icon')
|
||||
).click((e) => {
|
||||
e.preventDefault()
|
||||
this.remove()
|
||||
return false
|
||||
})
|
||||
)
|
||||
)
|
||||
}
|
||||
edit() {
|
||||
this.modal.find('form').trigger('reset')
|
||||
this.modal.find('form').find("[name='id']").val(this.id)
|
||||
this.modal.find('form').find("[name='nombre']").val(this.nombre)
|
||||
this.modal.find('form').find("#tipos").dropdown('set selected', this.tipo.id)
|
||||
modalToEdit(this.modal)
|
||||
this.modal.modal('show')
|
||||
}
|
||||
remove() {
|
||||
sendDelete(_urls.api + '/categoria/' + this.id + '/delete').then(() => {
|
||||
categorias.getCategorias()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const categorias = {
|
||||
id: '#categorias',
|
||||
categorias: [],
|
||||
modal: null,
|
||||
getCategorias: function() {
|
||||
return $.ajax({
|
||||
url: _urls.api + '/categorias',
|
||||
method: 'GET',
|
||||
dataType: 'json'
|
||||
}).then((data) => {
|
||||
if (data.categorias === null || data.categorias.length == 0) {
|
||||
this.categorias = []
|
||||
return sendGet(_urls.api + '/categorias').then((data) => {
|
||||
if (data.categorias === null || data.categorias.length === 0) {
|
||||
return
|
||||
}
|
||||
this.categorias = data.categorias
|
||||
$.each(data.categorias, (i, el) => {
|
||||
const cat = new Categoria(el)
|
||||
cat.setModal(this.modal)
|
||||
this.categorias.push(cat)
|
||||
})
|
||||
}).then(() => {
|
||||
this.draw()
|
||||
})
|
||||
},
|
||||
getTipos: function() {
|
||||
sendGet(_urls.api + '/tipos/categorias').then((data) => {
|
||||
this.modal.find('#tipos').dropdown()
|
||||
let values = []
|
||||
$.each(data.tipos, (i, el) => {
|
||||
values.push({value: el.id, text: el.descripcion, name: el.descripcion})
|
||||
})
|
||||
this.modal.find('#tipos').dropdown('change values', values)
|
||||
})
|
||||
},
|
||||
getParent: function() {
|
||||
let parent = $(this.id).find('tbody')
|
||||
if (parent.length == 0) {
|
||||
if (parent.length === 0) {
|
||||
const table = $('<table></table>').attr('class', 'ui table').append(
|
||||
$('<thead></thead>').append(
|
||||
$('<tr></tr>').append(
|
||||
$('<th></th>').html('Categoría')
|
||||
).append(
|
||||
$('<th></th>').html('Tipo')
|
||||
).append(
|
||||
$('<th></th>').attr('class', 'right aligned').append(
|
||||
$('<button></button>').attr('class', 'ui tiny green circular icon button').append(
|
||||
@ -47,27 +111,31 @@ const categorias = {
|
||||
const parent = this.getParent()
|
||||
parent.html('')
|
||||
$.each(this.categorias, (i, el) => {
|
||||
parent.append(
|
||||
$('<tr></tr>').append(
|
||||
$('<td></td>').html(el.nombre)
|
||||
)
|
||||
)
|
||||
parent.append(el.draw())
|
||||
})
|
||||
},
|
||||
add: function() {
|
||||
this.modal.find('form').trigger('reset')
|
||||
modalToAdd(this.modal)
|
||||
this.modal.modal('show')
|
||||
},
|
||||
doAdd: function() {
|
||||
const data = JSON.stringify({
|
||||
nombre: $("[name='nombre']").val()
|
||||
nombre: $("[name='nombre']").val(),
|
||||
tipo_id: $("[name='tipo']").val()
|
||||
})
|
||||
return $.ajax({
|
||||
url: _urls.api + '/categorias/add',
|
||||
method: 'POST',
|
||||
data: data,
|
||||
dataType: 'json'
|
||||
}).then((data) => {
|
||||
return sendPost(_urls.api + '/categorias/add', data).then((data) => {
|
||||
this.modal.modal('hide')
|
||||
this.getCategorias()
|
||||
})
|
||||
},
|
||||
doEdit: function() {
|
||||
const id = $("[name='id']").val()
|
||||
const data = JSON.stringify({
|
||||
nombre: $("[name='nombre']").val(),
|
||||
tipo_id: $("[name='tipo']").val()
|
||||
})
|
||||
return sendPut(_urls.api + '/categoria/' + id +'/edit', data).then((data) => {
|
||||
this.modal.modal('hide')
|
||||
this.getCategorias()
|
||||
})
|
||||
@ -80,9 +148,16 @@ const categorias = {
|
||||
})
|
||||
this.modal.find('form').submit((e) => {
|
||||
e.preventDefault()
|
||||
this.doAdd()
|
||||
const add = $(e.currentTarget).find('.plus.icon')
|
||||
if (add.length > 0) {
|
||||
this.doAdd()
|
||||
} else {
|
||||
this.doEdit()
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
this.getTipos()
|
||||
},
|
||||
setup: function() {
|
||||
this.setupModal()
|
||||
|
80
ui/public/assets/scripts/colorpicker.js
Normal file
80
ui/public/assets/scripts/colorpicker.js
Normal file
@ -0,0 +1,80 @@
|
||||
class Color {
|
||||
constructor({hex, red, green, blue}) {
|
||||
this.hex = hex ?? 'ffffff'
|
||||
this.red = red ?? 255
|
||||
this.green = green ?? 255
|
||||
this.blue = blue ?? 255
|
||||
}
|
||||
toHex() {
|
||||
this.hex = this.red.toString(16).padStart(2, '0') + this.green.toString(16).padStart(2, '0') + this.blue.toString(16).padStart(2, '0')
|
||||
return this.hex
|
||||
}
|
||||
toRGB() {
|
||||
this.red = parseInt(this.hex.substring(0,2), 16)
|
||||
this.green = parseInt(this.hex.substring(2,4), 16)
|
||||
this.blue = parseInt(this.hex.substring(4), 16)
|
||||
return [this.red, this.green, this.blue]
|
||||
}
|
||||
}
|
||||
class ColorPicker {
|
||||
constructor(elem) {
|
||||
this.setup(elem)
|
||||
}
|
||||
setup(elem) {
|
||||
this.elem = elem
|
||||
this.color = new Color({})
|
||||
this.color.hex = elem.val()
|
||||
this.color.toRGB()
|
||||
this.holder = $('<div></div>').attr('class', 'color_picker_holder ui horizontal segments')
|
||||
const red = $('<div></div>').attr('class', 'ui basic segment').append($('<div></div>').attr('class', 'ui red slider').slider({
|
||||
max: 255,
|
||||
start: this.color.red,
|
||||
onMove: (content) => {
|
||||
this.color.red = content
|
||||
this.update()
|
||||
}
|
||||
}))
|
||||
const green = $('<div></div>').attr('class', 'ui basic segment').append($('<div></div>').attr('class', 'ui green slider').slider({
|
||||
max: 255,
|
||||
start: this.color.green,
|
||||
onMove: (content) => {
|
||||
this.color.green = content
|
||||
this.update()
|
||||
}
|
||||
}))
|
||||
const blue = $('<div></div>').attr('class', 'ui basic segment').append($('<div></div>').attr('class', 'ui blue slider').slider({
|
||||
max: 255,
|
||||
start: this.color.blue,
|
||||
onMove: (content) => {
|
||||
this.color.blue = content
|
||||
this.update()
|
||||
}
|
||||
}))
|
||||
const color_cell = $('<div></div>').attr('class', 'ui center aligned compact basic segment').append(
|
||||
$('<i></i>').attr('class', 'massive icons').append(
|
||||
$('<i></i>').attr('class', 'square icon color_cell').css('color', '#' + this.color.toHex())
|
||||
).append(
|
||||
$('<i></i>').attr('class', 'square outline icon')
|
||||
)
|
||||
)
|
||||
this.holder.append(color_cell)
|
||||
const vseg = $('<div></div>').attr('class', 'ui basic segments')
|
||||
vseg.append(red)
|
||||
vseg.append(green)
|
||||
vseg.append(blue)
|
||||
this.holder.append($('<div></div>').attr('class', 'ui basic segment').append(vseg))
|
||||
this.elem.after(this.holder)
|
||||
}
|
||||
setColor(color) {
|
||||
this.color.hex = color
|
||||
this.color.toRGB()
|
||||
this.update()
|
||||
}
|
||||
update() {
|
||||
this.elem.val(this.color.toHex())
|
||||
this.holder.find('.red').slider('set value', this.color.red, false)
|
||||
this.holder.find('.green').slider('set value', this.color.green, false)
|
||||
this.holder.find('.blue').slider('set value', this.color.blue, false)
|
||||
this.holder.find('.color_cell').css('color', '#' + this.color.toHex())
|
||||
}
|
||||
}
|
@ -1,42 +1,126 @@
|
||||
class Cuenta {
|
||||
constructor({id, nombre, categoria_id, tipo_id, moneda_id, categoria, tipo, moneda, saldo, saldoFormateado}) {
|
||||
this.id = id
|
||||
this.nombre = nombre
|
||||
this.categoria_id = categoria_id
|
||||
this.tipo_id = tipo_id
|
||||
this.moneda_id = moneda_id
|
||||
this.categoria = categoria
|
||||
this.tipo = tipo
|
||||
this.moneda = moneda
|
||||
this.modal = null
|
||||
}
|
||||
setModal(modal) {
|
||||
this.modal = modal
|
||||
}
|
||||
draw() {
|
||||
return $('<tr></tr>').append(
|
||||
$('<td></td>').html(this.nombre)
|
||||
).append(
|
||||
$('<td></td>').html(this.categoria.nombre + ' - ' + this.categoria.tipo.descripcion)
|
||||
).append(
|
||||
$('<td></td>').css('color', '#' + this.tipo.color).html(this.tipo.descripcion)
|
||||
).append(
|
||||
$('<td></td>').html(this.moneda.codigo)
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').append(
|
||||
$('<button></button>').attr('class', 'ui tiny circular icon button').attr('data-id', this.id).append(
|
||||
$('<i></i>').attr('class', 'edit icon')
|
||||
).click((e) => {
|
||||
e.preventDefault()
|
||||
this.edit()
|
||||
return false
|
||||
})
|
||||
).append(
|
||||
$('<button></button>').attr('class', 'ui tiny circular red icon button').attr('data-id', this.id).append(
|
||||
$('<i></i>').attr('class', 'remove icon')
|
||||
).click((e) => {
|
||||
e.preventDefault()
|
||||
this.remove()
|
||||
return false
|
||||
})
|
||||
)
|
||||
)
|
||||
}
|
||||
edit() {
|
||||
const form = this.modal.find('form')
|
||||
form.trigger('reset')
|
||||
form.find("[name='id']").val(this.id)
|
||||
form.find("[name='nombre']").val(this.nombre)
|
||||
form.find("[name='categoria']").dropdown('set selected', this.categoria.id)
|
||||
form.find("[name='tipo']").dropdown('set selected', this.tipo.id)
|
||||
form.find("[name='moneda']").dropdown('set selected', this.moneda.id)
|
||||
modalToEdit(this.modal)
|
||||
this.modal.modal('show')
|
||||
}
|
||||
remove() {
|
||||
sendDelete(_urls.api + '/cuenta/' + this.id + '/delete').then(() => {
|
||||
cuentas.get().cuentas()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const cuentas = {
|
||||
id: '#cuentas',
|
||||
cuentas: [],
|
||||
categorias: [],
|
||||
getCuentas: function() {
|
||||
return $.ajax({
|
||||
url: _urls.api + '/cuentas',
|
||||
method: 'GET',
|
||||
dataType: 'json'
|
||||
}).then((data) => {
|
||||
if (data.cuentas === null || data.cuentas.length == 0) {
|
||||
return
|
||||
tipos: [],
|
||||
get: function() {
|
||||
return {
|
||||
cuentas: () => {
|
||||
this.cuentas = []
|
||||
return sendGet(_urls.api + '/cuentas').then((data) => {
|
||||
if (data.cuentas === null || data.cuentas.length === 0) {
|
||||
return
|
||||
}
|
||||
$.each(data.cuentas, (i, el) => {
|
||||
const cuenta = new Cuenta(el)
|
||||
cuenta.setModal(this.modal)
|
||||
this.cuentas.push(cuenta)
|
||||
})
|
||||
}).then(() => {
|
||||
this.draw().cuentas()
|
||||
})
|
||||
},
|
||||
categorias: () => {
|
||||
return sendGet(_urls.api + '/categorias').then((data) => {
|
||||
if (data.categorias === null || data.categorias.length === 0) {
|
||||
return
|
||||
}
|
||||
this.categorias = data.categorias
|
||||
}).then(() => {
|
||||
this.draw().categorias()
|
||||
})
|
||||
},
|
||||
tipos: () => {
|
||||
return sendGet(_urls.api + '/tipos/cuentas').then((data) => {
|
||||
if (data.tipos === null || data.tipos.length === 0) {
|
||||
return
|
||||
}
|
||||
this.tipos = data.tipos
|
||||
}).then(() => {
|
||||
this.draw().tipos()
|
||||
})
|
||||
},
|
||||
monedas: () => {
|
||||
return sendGet(_urls.api + '/monedas').then((data) => {
|
||||
if (data.monedas === null || data.monedas.length === 0) {
|
||||
return
|
||||
}
|
||||
this.monedas = data.monedas
|
||||
}).then(() => {
|
||||
this.draw().monedas()
|
||||
})
|
||||
},
|
||||
parent: () => {
|
||||
const segment = $(this.id)
|
||||
let parent = segment.find('tbody')
|
||||
if (parent.length === 0) {
|
||||
parent = this.buildParent(segment)
|
||||
}
|
||||
return parent
|
||||
}
|
||||
this.cuentas = data.cuentas
|
||||
}).then(() => {
|
||||
this.draw()
|
||||
})
|
||||
},
|
||||
getCategorias: function() {
|
||||
return $.ajax({
|
||||
url: _urls.api + '/categorias',
|
||||
method: 'GET',
|
||||
dataType: 'json'
|
||||
}).then((data) => {
|
||||
if (data.categorias === null || data.categorias.length == 0) {
|
||||
return
|
||||
}
|
||||
this.categorias = data.categorias
|
||||
}).then(() => {
|
||||
this.drawCategorias()
|
||||
})
|
||||
},
|
||||
drawCategorias: function() {
|
||||
const select = $("[name='categoria']")
|
||||
$.each(this.categorias, (i, el) => {
|
||||
select.append(
|
||||
$('<option></option>').attr('value', el.id).html(el.nombre)
|
||||
)
|
||||
})
|
||||
}
|
||||
},
|
||||
buildParent: function(segment) {
|
||||
const table = $('<table></table>').attr('class', 'ui table').append(
|
||||
@ -45,6 +129,10 @@ const cuentas = {
|
||||
$('<th></th>').html('Cuenta')
|
||||
).append(
|
||||
$('<th></th>').html('Categoría')
|
||||
).append(
|
||||
$('<th></th>').html('Tipo')
|
||||
).append(
|
||||
$('<th></th>').html('Moneda')
|
||||
).append(
|
||||
$('<th></th>').attr('class', 'right aligned').append(
|
||||
$('<button></button>').attr('class', 'ui tiny green circular icon button').append(
|
||||
@ -64,44 +152,73 @@ const cuentas = {
|
||||
segment.append(table)
|
||||
return parent
|
||||
},
|
||||
getParent: function() {
|
||||
const segment = $(this.id)
|
||||
let parent = segment.find('tbody')
|
||||
if (parent.length == 0) {
|
||||
parent = this.buildParent(segment)
|
||||
}
|
||||
return parent
|
||||
},
|
||||
draw: function() {
|
||||
const parent = this.getParent()
|
||||
parent.html('')
|
||||
$.each(this.cuentas, (i, el) => {
|
||||
parent.append(
|
||||
$('<tr></tr>').append(
|
||||
$('<td></td>').html(el.nombre)
|
||||
).append(
|
||||
$('<td></td>').html(el.categoria.nombre)
|
||||
)
|
||||
)
|
||||
})
|
||||
return {
|
||||
cuentas: () => {
|
||||
const parent = this.get().parent()
|
||||
parent.html('')
|
||||
$.each(this.cuentas, (i, el) => {
|
||||
parent.append(el.draw())
|
||||
})
|
||||
},
|
||||
categorias: () => {
|
||||
const select = $("[name='categoria']")
|
||||
$.each(this.categorias, (i, el) => {
|
||||
select.append(
|
||||
$('<option></option>').attr('value', el.id).html(el.nombre + ' - ' + el.tipo.descripcion)
|
||||
)
|
||||
})
|
||||
},
|
||||
tipos: () => {
|
||||
const select = $("[name='tipo']")
|
||||
$.each(this.tipos, (i, el) => {
|
||||
select.append($('<option></option>').attr('value', el.id).html(el.descripcion))
|
||||
})
|
||||
},
|
||||
monedas: () => {
|
||||
const select = $("[name='moneda']")
|
||||
$.each(this.monedas, (i, el) => {
|
||||
const opt = $('<option></option>').attr('value', el.id).html(el.denominacion)
|
||||
if (el.codigo === 'CLP') {
|
||||
opt.attr('selected', 'selected')
|
||||
}
|
||||
select.append(opt)
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
add: function() {
|
||||
this.modal.find('form').trigger('reset')
|
||||
modalToAdd(this.modal)
|
||||
this.modal.modal('show')
|
||||
},
|
||||
doAdd: function() {
|
||||
const data = JSON.stringify({
|
||||
categoria_id: $("[name='categoria']").val(),
|
||||
nombre: $("[name='nombre']").val()
|
||||
nombre: $("[name='nombre']").val(),
|
||||
tipo_id: $("[name='tipo']").val(),
|
||||
moneda_id: $("[name='moneda']").val()
|
||||
})
|
||||
return $.ajax({
|
||||
url: _urls.api + '/cuentas/add',
|
||||
method: 'POST',
|
||||
data: data,
|
||||
dataType: 'json'
|
||||
}).then((data) => {
|
||||
return sendPost(
|
||||
_urls.api + '/cuentas/add',
|
||||
data
|
||||
).then((data) => {
|
||||
this.modal.modal('hide')
|
||||
this.getCuentas()
|
||||
this.get().cuentas()
|
||||
})
|
||||
},
|
||||
doEdit: function() {
|
||||
form = this.modal.find('form')
|
||||
const id = form.find("[name='id']").val()
|
||||
const data = JSON.stringify({
|
||||
nombre: form.find("[name='nombre']").val(),
|
||||
categoria_id: form.find("[name='categoria']").val(),
|
||||
tipo_id: form.find("[name='tipo']").val(),
|
||||
moneda_id: form.find("[name='moneda']").val()
|
||||
})
|
||||
sendPut(_urls.api + '/cuenta/' + id + '/edit', data).then(() => {
|
||||
this.modal.modal('hide')
|
||||
this.get().cuentas()
|
||||
})
|
||||
},
|
||||
setupModal: function() {
|
||||
@ -112,14 +229,23 @@ const cuentas = {
|
||||
})
|
||||
this.modal.find('form').submit((e) => {
|
||||
e.preventDefault()
|
||||
this.doAdd()
|
||||
const add = $(e.currentTarget).find('.ui.button').find('.plus.icon')
|
||||
if (add.length > 0) {
|
||||
this.doAdd()
|
||||
} else {
|
||||
this.doEdit()
|
||||
}
|
||||
return false
|
||||
})
|
||||
},
|
||||
setup: function() {
|
||||
this.setupModal()
|
||||
this.getCuentas().then(() => {
|
||||
this.getCategorias()
|
||||
this.get().cuentas().then(() => {
|
||||
this.get().categorias().then(() => {
|
||||
this.get().tipos().then(() => {
|
||||
this.get().monedas()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,85 @@
|
||||
class Transaccion {
|
||||
constructor({id, debito_id, credito_id, fecha, glosa, detalle, valor, debito, credito, fechaFormateada, valorFormateado}) {
|
||||
this.id = id
|
||||
this.debito_id = debito_id
|
||||
this.credito_id = credito_id
|
||||
this.fecha = {
|
||||
fecha,
|
||||
formateada: fechaFormateada
|
||||
}
|
||||
this.glosa = glosa
|
||||
this.detalle = detalle
|
||||
this.valor = {
|
||||
valor,
|
||||
formateado: valorFormateado
|
||||
}
|
||||
this.debito = debito
|
||||
this.credito = credito
|
||||
this.modal = null
|
||||
}
|
||||
setCuenta(cuenta) {
|
||||
this.cuenta = cuenta
|
||||
}
|
||||
setModal(modal) {
|
||||
this.modal = modal
|
||||
}
|
||||
isDebito() {
|
||||
return this.debito.id === this.cuenta.id;
|
||||
}
|
||||
isIncrement() {
|
||||
const debits = ['Activo', 'Perdida']
|
||||
if (debits.indexOf(this.cuenta.tipo.descripcion)) {
|
||||
return this.isDebito()
|
||||
}
|
||||
return !this.isDebito()
|
||||
}
|
||||
draw({saldo, format}) {
|
||||
const fuente = (this.isDebito()) ? this.credito : this.debito
|
||||
return $('<tr></tr>').append(
|
||||
$('<td></td>').html(this.fecha.formateada)
|
||||
).append(
|
||||
$('<td></td>').append(
|
||||
$('<a></a>').attr('href', _urls.base + 'cuenta/' + fuente.id).html(fuente.nombre + ' (' + fuente.categoria.nombre + ')')
|
||||
)
|
||||
).append(
|
||||
$('<td></td>').html(this.glosa + '<br />' + this.detalle)
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').html((this.isIncrement()) ? '' : format.format(this.valor.valor))
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').html((this.isIncrement()) ? format.format(this.valor.valor) : '')
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').html(format.format(saldo))
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned')/*.append(
|
||||
$('<button></button>').attr('class', 'ui tiny circular icon button').append(
|
||||
$('<i></i>').attr('class', 'edit icon')
|
||||
).click((e) => {
|
||||
e.preventDefault()
|
||||
this.edit()
|
||||
return false
|
||||
})
|
||||
)*/.append(
|
||||
$('<button></button>').attr('class', 'ui tiny circular red icon button').append(
|
||||
$('<i></i>').attr('class', 'remove icon')
|
||||
).click((e) => {
|
||||
e.preventDefault()
|
||||
this.remove()
|
||||
return false
|
||||
})
|
||||
)
|
||||
)
|
||||
}
|
||||
edit() {
|
||||
const form = this.modal.find('form')
|
||||
form.find("[name='fecha']")
|
||||
}
|
||||
remove() {
|
||||
sendDelete(_urls.api + '/transaccion/' + this.id + '/delete').then(() => {
|
||||
transacciones.get().transacciones()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const transacciones = {
|
||||
id: '#transacciones',
|
||||
cuenta_id: 0,
|
||||
@ -9,49 +91,50 @@ const transacciones = {
|
||||
return {
|
||||
transacciones: () => {
|
||||
let promises = []
|
||||
$.ajax({
|
||||
url: _urls.api + '/cuenta/' + this.cuenta_id + '/transacciones/amount',
|
||||
method: 'GET',
|
||||
dataType: 'json'
|
||||
}).then((data) => {
|
||||
const amount = data.transacciones
|
||||
const step = 100
|
||||
for (let i = 0; i < amount; i += step) {
|
||||
promises.push($.ajax({
|
||||
url: _urls.api + '/cuenta/' + this.cuenta_id + '/transacciones/' + step + '/' + i,
|
||||
method: 'GET',
|
||||
dataType: 'json'
|
||||
}))
|
||||
sendGet(_urls.api + '/cuenta/' + this.cuenta_id + '/transacciones/amount').then((data) => {
|
||||
if (data.cuenta === null) {
|
||||
return
|
||||
}
|
||||
Promise.all(promises).then((data_arr) => {
|
||||
if (data_arr[0].cuenta === null) {
|
||||
return
|
||||
}
|
||||
this.cuenta = data_arr[0].cuenta
|
||||
this.saldo = this.cuenta.saldo
|
||||
$('#cuenta').html(this.cuenta.nombre + ' (' + this.cuenta.categoria.nombre + ')')
|
||||
this.transacciones = []
|
||||
data_arr.forEach(data => {
|
||||
if (data.transacciones === null || data.transacciones.length == 0) {
|
||||
return
|
||||
}
|
||||
this.transacciones.push(...data.transacciones)
|
||||
this.cuenta = data.cuenta
|
||||
this.saldo = this.cuenta.saldo
|
||||
$('#cuenta').html(this.cuenta.nombre + ' (' + this.cuenta.categoria.nombre + ')').append(
|
||||
$('<i></i>').attr('class', 'square full icon').css('color', '#' + this.cuenta.tipo.color)
|
||||
)
|
||||
const amount = data.transacciones
|
||||
const step = 50
|
||||
for (let i = 0; i < amount; i += step) {
|
||||
promises.push(
|
||||
sendGet(_urls.api + '/cuenta/' + this.cuenta_id + '/transacciones/' + step + '/' + i)
|
||||
)
|
||||
}
|
||||
if (promises.length > 0) {
|
||||
Promise.all(promises).then((data_arr) => {
|
||||
this.transacciones = []
|
||||
data_arr.forEach(data => {
|
||||
if (data.transacciones === null || data.transacciones.length === 0) {
|
||||
return
|
||||
}
|
||||
$.each(data.transacciones, (i, el) => {
|
||||
const tr = new Transaccion(el)
|
||||
tr.setCuenta(this.cuenta)
|
||||
tr.setModal(this.modal)
|
||||
this.transacciones.push(tr)
|
||||
})
|
||||
})
|
||||
this.transacciones.sort((a, b) => {
|
||||
return (new Date(b.fecha)) - (new Date(a.fecha))
|
||||
})
|
||||
}).then(() => {
|
||||
this.draw()
|
||||
})
|
||||
this.transacciones.sort((a, b) => {
|
||||
return (new Date(b.fecha)) - (new Date(a.fecha))
|
||||
})
|
||||
}).then(() => {
|
||||
} else {
|
||||
this.draw()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
cuentas: () => {
|
||||
return $.ajax({
|
||||
url: _urls.api + '/cuentas',
|
||||
method: 'GET',
|
||||
dataType: 'json'
|
||||
}).then((data) => {
|
||||
if (data.cuentas === null || data.cuentas.length == 0) {
|
||||
return sendGet(_urls.api + '/cuentas').then((data) => {
|
||||
if (data.cuentas === null || data.cuentas.length === 0) {
|
||||
return
|
||||
}
|
||||
this.cuentas = data.cuentas
|
||||
@ -67,29 +150,12 @@ const transacciones = {
|
||||
}
|
||||
},
|
||||
draw: function() {
|
||||
const format = Intl.NumberFormat('es-CL', {style: 'currency', currency: 'CLP'})
|
||||
const format = Intl.NumberFormat('es-CL', {style: 'currency', currency: this.cuenta.moneda.codigo})
|
||||
const parent = $(this.id)
|
||||
parent.html('')
|
||||
$.each(this.transacciones, (i, el) => {
|
||||
const fuente = (el.valor < 0) ? el.hasta : el.desde
|
||||
parent.append(
|
||||
$('<tr></tr>').append(
|
||||
$('<td></td>').html(el.fechaFormateada)
|
||||
).append(
|
||||
$('<td></td>').append(
|
||||
$('<a></a>').attr('href', _urls.base + 'cuenta/' + fuente.id).html(fuente.nombre + ' (' + fuente.categoria.nombre + ')')
|
||||
)
|
||||
).append(
|
||||
$('<td></td>').html(el.glosa + '<br />' + el.detalle)
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').html((el.valor < 0) ? '' : el.valorFormateado.replace('-', ''))
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').html((el.valor < 0) ? el.valorFormateado.replace('-', '') : '')
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').html(format.format(this.saldo))
|
||||
)
|
||||
)
|
||||
this.saldo -= parseInt(el.valor)
|
||||
parent.append(el.draw({saldo: this.saldo, format: format}))
|
||||
this.saldo = this.saldo + parseInt(el.valor.valor) * ((el.isIncrement()) ? 1 : -1)
|
||||
})
|
||||
},
|
||||
add: function() {
|
||||
@ -99,22 +165,26 @@ const transacciones = {
|
||||
this.modal.modal('show')
|
||||
},
|
||||
exec: () => {
|
||||
const fecha = $("[name='fecha']").val()
|
||||
const data1 = JSON.stringify({
|
||||
desde_id: $("[name='moneda']").val(),
|
||||
hasta_id: 1,
|
||||
fecha: fecha,
|
||||
valor: $("[name='cambio']").val()
|
||||
})
|
||||
sendPut(_urls.api + '/tipos/cambios/add', data1)
|
||||
|
||||
const valor = $("[name='valor']").val()
|
||||
const cuenta = $("[name='cuenta']").val()
|
||||
const data = JSON.stringify({
|
||||
desde_id: (valor < 0) ? this.cuenta_id : cuenta,
|
||||
hasta_id: (valor < 0) ? cuenta : this.cuenta_id,
|
||||
fecha: $("[name='fecha']").val(),
|
||||
debito_id: (valor < 0) ? this.cuenta_id : cuenta,
|
||||
credito_id: (valor < 0) ? cuenta : this.cuenta_id,
|
||||
fecha: fecha,
|
||||
glosa: $("[name='glosa']").val(),
|
||||
detalle: $("[name='detalle']").val(),
|
||||
valor: (valor < 0) ? -valor : valor
|
||||
})
|
||||
return $.ajax({
|
||||
url: _urls.api + '/transacciones/add',
|
||||
method: 'POST',
|
||||
data: data,
|
||||
dataType: 'json'
|
||||
}).then(() => {
|
||||
return sendPost(_urls.api + '/transacciones/add', data).then(() => {
|
||||
this.modal.modal('hide')
|
||||
this.get().transacciones()
|
||||
})
|
||||
|
@ -1,19 +1,234 @@
|
||||
const down_icon = 'right chevron'
|
||||
const up_icon = 'down chevron'
|
||||
|
||||
class Cuenta {
|
||||
constructor({id, nombre, tipo_id, categoria_id, tipo, saldo, saldoFormateado}) {
|
||||
this.id = id
|
||||
this.nombre = nombre
|
||||
this.tipo_id = tipo_id
|
||||
this.categoria_id = categoria_id
|
||||
this.tipo = tipo
|
||||
this.saldo = {
|
||||
saldo,
|
||||
formateado: saldoFormateado
|
||||
}
|
||||
}
|
||||
setTipos(tipos) {
|
||||
this.tipos = tipos
|
||||
}
|
||||
draw() {
|
||||
const tr = $('<tr></tr>').attr('data-id', this.id).attr('data-class', 'cuenta').append(
|
||||
$('<td></td>').append(
|
||||
$('<i></i>').attr('class', 'angle right icon')
|
||||
)
|
||||
).append(
|
||||
$('<td></td>').append(
|
||||
$('<i></i>').attr('class', 'angle right icon')
|
||||
)
|
||||
).append(
|
||||
$('<td></td>').append(
|
||||
$('<a></a>').attr('href', _urls.base + 'cuenta/' + this.id).append(
|
||||
$('<i></i>').attr('class', 'square full icon').css('color', '#' + this.tipo.color)
|
||||
).append(this.nombre)
|
||||
)
|
||||
)
|
||||
$.each(this.tipos, (i, m) => {
|
||||
const td = $('<td></td>').attr('class', 'right aligned')
|
||||
if (m.descripcion === this.tipo.descripcion) {
|
||||
td.html(this.saldo.formateado)
|
||||
}
|
||||
tr.append(td)
|
||||
})
|
||||
$("[data-id='" + this.categoria_id + "'][data-class='categoria']").after(tr)
|
||||
}
|
||||
remove() {
|
||||
$("[data-id='" + this.id + "'][data-class='cuenta']").remove()
|
||||
}
|
||||
}
|
||||
class Categoria {
|
||||
constructor({id, nombre, tipo_id, tipo, activos, pasivos, ganancias, perdidas}) {
|
||||
this.id = id
|
||||
this.nombre = nombre
|
||||
this.tipo_id = tipo_id
|
||||
this.tipo = tipo
|
||||
this.activos = activos
|
||||
this.pasivos = pasivos
|
||||
this.ganancias = ganancias
|
||||
this.perdidas = perdidas
|
||||
this.is_open = false
|
||||
this.cuentas = []
|
||||
}
|
||||
setTipos(tipos) {
|
||||
this.tipos = tipos
|
||||
}
|
||||
draw({format}) {
|
||||
const button = $('<button></button>').attr('class', 'ui mini compact icon button').append(
|
||||
$('<i></i>').attr('class', down_icon + ' icon')
|
||||
).click((e) => {
|
||||
const plus = button.find('.' + down_icon.replace(' ', '.') + '.icon')
|
||||
if (plus.length > 0) {
|
||||
this.loadCuentas()
|
||||
button.find('i.icon').removeClass(down_icon).addClass(up_icon)
|
||||
this.is_open = true
|
||||
} else {
|
||||
this.removeCuentas()
|
||||
button.find('i.icon').removeClass(up_icon).addClass(down_icon)
|
||||
this.is_open = false
|
||||
}
|
||||
})
|
||||
const tr = $('<tr></tr>').attr('data-id', this.id).attr('data-class', 'categoria').append(
|
||||
$('<td></td>').append($('<span></span>').html('<i class="angle right icon"></i>'))
|
||||
).append(
|
||||
$('<td></td>').attr('colspan', 2).append(
|
||||
$('<div></div>').append(button).append(this.nombre)
|
||||
)
|
||||
)
|
||||
$.each(this.tipos, (i, el) => {
|
||||
tr.append(
|
||||
$('<td></td>').attr('class', 'right aligned').html(format.format(this[el.descripcion.toLowerCase() + 's']))
|
||||
)
|
||||
})
|
||||
$("[data-id='" + this.tipo_id + "'][data-class='tipo_categoria']").after(tr)
|
||||
if (this.is_open) {
|
||||
button.trigger('click')
|
||||
}
|
||||
}
|
||||
remove() {
|
||||
this.removeCuentas()
|
||||
$("[data-id='" + this.id + "'][data-class='categoria']").remove()
|
||||
}
|
||||
loadCuentas() {
|
||||
if (this.cuentas.length === 0) {
|
||||
sendGet(_urls.api + '/categoria/' + this.id + '/cuentas').then((data) => {
|
||||
if (data.cuentas === null || data.cuentas.length === 0) {
|
||||
return
|
||||
}
|
||||
$.each(data.cuentas, (i, el) => {
|
||||
const cuenta = new Cuenta(el)
|
||||
cuenta.setTipos(this.tipos)
|
||||
this.cuentas.push(cuenta)
|
||||
})
|
||||
}).then(() => {
|
||||
this.drawCuentas()
|
||||
})
|
||||
return
|
||||
}
|
||||
this.drawCuentas()
|
||||
}
|
||||
drawCuentas() {
|
||||
if (this.cuentas.length === 0) {
|
||||
$("[data-id='"+this.id+"'][data-class='categoria']").after(
|
||||
$('<tr></tr>').attr('data-class', 'cuenta').attr('data-id', 'vacio').append(
|
||||
$('<td></td>')
|
||||
).append(
|
||||
$('<td></td>')
|
||||
).append(
|
||||
$('<td></td>').attr('colspan', 5).html('No hay cuentas.')
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
$.each(this.cuentas, (i, el) => {
|
||||
el.draw()
|
||||
})
|
||||
}
|
||||
removeCuentas() {
|
||||
if (this.cuentas.length === 0) {
|
||||
$("tr[data-class='cuenta'][data-id='vacio']").remove()
|
||||
return
|
||||
}
|
||||
$.each(this.cuentas, (i, el) => {
|
||||
el.remove()
|
||||
})
|
||||
}
|
||||
}
|
||||
class TipoCategoria {
|
||||
constructor({id, descripcion, activo, activos, pasivos, ganancias, perdidas}) {
|
||||
this.id = id
|
||||
this.descripcion = descripcion
|
||||
this.activo = activo
|
||||
this.activos = activos
|
||||
this.pasivos = pasivos
|
||||
this.ganancias = ganancias
|
||||
this.perdidas = perdidas
|
||||
this.categorias = []
|
||||
}
|
||||
setTipos(tipos) {
|
||||
this.tipos = tipos
|
||||
}
|
||||
draw({format}) {
|
||||
const button = $('<button></button>').attr('class', 'ui mini compact icon button').append(
|
||||
$('<i></i>').attr('class', down_icon + ' icon')
|
||||
).click((e) => {
|
||||
const plus = button.find('.' + down_icon.replace(' ', '.') + '.icon')
|
||||
if (plus.length > 0) {
|
||||
this.loadCategorias()
|
||||
button.find('i.icon').removeClass(down_icon).addClass(up_icon)
|
||||
} else {
|
||||
this.removeCategorias()
|
||||
button.find('i.icon').removeClass(up_icon).addClass(down_icon)
|
||||
}
|
||||
})
|
||||
const tr = $('<tr></tr>').attr('data-id', this.id).attr('data-class', 'tipo_categoria').append(
|
||||
$('<td></td>').attr('colspan', 3).append(
|
||||
$('<div></div>').append(button).append(this.descripcion)
|
||||
)
|
||||
)
|
||||
$.each(this.tipos, (i, el) => {
|
||||
tr.append($('<td></td>').attr('class', 'right aligned').html(format.format(this[el.descripcion.toLowerCase() + 's'])))
|
||||
})
|
||||
return tr
|
||||
}
|
||||
loadCategorias() {
|
||||
if (this.categorias.length === 0) {
|
||||
sendGet(_urls.api + '/tipos/categoria/' + this.id + '/categorias').then((data) => {
|
||||
if (data.categorias === null || data.categorias.length === 0) {
|
||||
return
|
||||
}
|
||||
$.each(data.categorias, (i, el) => {
|
||||
const cat = new Categoria(el)
|
||||
cat.setTipos(this.tipos)
|
||||
this.categorias.push(cat)
|
||||
})
|
||||
}).then(() => {
|
||||
this.drawCategorias()
|
||||
})
|
||||
return
|
||||
}
|
||||
this.drawCategorias()
|
||||
}
|
||||
drawCategorias() {
|
||||
const format = Intl.NumberFormat('es-CL', {style: 'currency', currency: 'CLP'})
|
||||
$.each(this.categorias, (i, el) => {
|
||||
el.draw({format})
|
||||
})
|
||||
}
|
||||
removeCategorias() {
|
||||
$.each(this.categorias, (i, el) => {
|
||||
el.remove()
|
||||
})
|
||||
}
|
||||
}
|
||||
const cuentas = {
|
||||
id: '#cuentas',
|
||||
categorias: [],
|
||||
id: 'cuentas',
|
||||
balance: 0,
|
||||
tipos: [],
|
||||
tipos_categorias: [],
|
||||
get: function() {
|
||||
return {
|
||||
parent: () => {
|
||||
let parent = $(this.id)
|
||||
let parent = $('#' + this.id)
|
||||
if (parent.length === 0) {
|
||||
const table = $('<table></table>').attr('class', 'ui striped table').append(
|
||||
$('<thead></thead>').append(
|
||||
$('<tr></tr>').append(
|
||||
$('<th></th>').html('Cuenta')
|
||||
).append(
|
||||
$('<th></th>').attr('class', 'right aligned').html('Saldo')
|
||||
)
|
||||
const tr = $('<tr></tr>').append(
|
||||
$('<th></th>').attr('colspan', 3).html('Cuenta')
|
||||
)
|
||||
$.each(this.tipos, (i, el) => {
|
||||
tr.append(
|
||||
$('<th></th>').attr('class', 'right aligned').css('color', '#' + el.color).html(el.descripcion)
|
||||
)
|
||||
})
|
||||
const table = $('<table></table>').attr('class', 'ui striped table').append(
|
||||
$('<thead></thead>').append(tr)
|
||||
)
|
||||
parent = $('<tbody></tbody>').attr('id', this.id)
|
||||
table.append(parent)
|
||||
@ -21,107 +236,74 @@ const cuentas = {
|
||||
}
|
||||
return parent
|
||||
},
|
||||
categorias: () => {
|
||||
return $.ajax({
|
||||
url: _urls.api + '/categorias',
|
||||
method: 'GET',
|
||||
dataType: 'json'
|
||||
}).then((data) => {
|
||||
if (data.categorias === null || data.categorias.length == 0) {
|
||||
tipos_cuentas: () => {
|
||||
return sendGet(_urls.api + '/tipos/cuentas').then((data) => {
|
||||
if (data.tipos === null || data.tipos.length === 0) {
|
||||
return
|
||||
}
|
||||
this.categorias = data.categorias
|
||||
}).then(() => {
|
||||
this.draw().categorias()
|
||||
this.tipos = data.tipos
|
||||
})
|
||||
},
|
||||
cuentas: (categoria_id) => {
|
||||
return $.ajax({
|
||||
url: _urls.api + '/categoria/' + categoria_id + '/cuentas',
|
||||
method: 'GET',
|
||||
dataType: 'json'
|
||||
}).then((data) => {
|
||||
if (data.cuentas === null || data.cuentas.length == 0) {
|
||||
tipos_categorias: () => {
|
||||
return sendGet(_urls.api + '/tipos/categorias').then((data) => {
|
||||
if (data.tipos === null || data.tipos.length === 0) {
|
||||
return
|
||||
}
|
||||
const idx = this.categorias.findIndex(el => {
|
||||
if (el.id == categoria_id) {
|
||||
return true
|
||||
}
|
||||
$.each(data.tipos, (i, el) => {
|
||||
tipo = new TipoCategoria(el)
|
||||
tipo.setTipos(this.tipos)
|
||||
this.tipos_categorias.push(tipo)
|
||||
})
|
||||
this.categorias[idx].cuentas = data.cuentas
|
||||
}).then(() => {
|
||||
this.draw().cuentas(categoria_id)
|
||||
this.draw().tipos_categorias()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
remove: function() {
|
||||
return {
|
||||
cuentas: (categoria_id) => {
|
||||
const idx = this.categorias.findIndex(el => {
|
||||
if (el.id == categoria_id) {
|
||||
return true
|
||||
}
|
||||
},
|
||||
balance: () => {
|
||||
sendGet(_urls.api + '/balance').then((data) => {
|
||||
this.balance = data
|
||||
}).then(() => {
|
||||
this.draw().balance()
|
||||
})
|
||||
const parent = $("[data-id='" + categoria_id + "']")
|
||||
for (let i = 0; i < this.categorias[idx].cuentas.length; i ++) {
|
||||
parent.next().remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
draw: function() {
|
||||
return {
|
||||
categorias: () => {
|
||||
tipos_categorias: () => {
|
||||
const format = Intl.NumberFormat('es-CL', {style: 'currency', currency: 'CLP'})
|
||||
const parent = this.get().parent()
|
||||
$.each(this.categorias, (i, el) => {
|
||||
const button = $('<button></button>').attr('class', 'ui mini compact icon button').append(
|
||||
$('<i></i>').attr('class', 'plus icon')
|
||||
).click((e) => {
|
||||
const plus = button.find('.plus')
|
||||
if (plus.length == 0) {
|
||||
console.debug(e.target)
|
||||
this.remove().cuentas(el.id)
|
||||
button.find('i.icon').removeClass('minus').addClass('plus')
|
||||
} else {
|
||||
console.debug(e.target)
|
||||
this.get().cuentas(el.id)
|
||||
button.find('i.icon').removeClass('plus').addClass('minus')
|
||||
}
|
||||
})
|
||||
const f = $('<tr></tr>').attr('data-id', el.id).append(
|
||||
$('<td></td>').append(
|
||||
$('<div></div>').append(button).append(el.nombre)
|
||||
)
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').html(el.saldoFormateado)
|
||||
)
|
||||
parent.append(f)
|
||||
$.each(this.tipos_categorias, (i, el) => {
|
||||
parent.append(el.draw({format, tipos: this.tipos}))
|
||||
})
|
||||
this.get().balance()
|
||||
},
|
||||
cuentas: (categoria_id) => {
|
||||
const idx = this.categorias.findIndex(el => {
|
||||
if (el.id == categoria_id) {
|
||||
return true
|
||||
}
|
||||
})
|
||||
const parent = $("[data-id='" + categoria_id + "']")
|
||||
$.each(this.categorias[idx].cuentas, (i, el) => {
|
||||
parent.after(
|
||||
$('<tr></tr>').attr('class', 'item').append(
|
||||
$('<td></td>').append(
|
||||
$('<a></a>').attr('href', _urls.base + 'cuenta/' + el.id).html(el.nombre)
|
||||
balance: () => {
|
||||
const parent = this.get().parent().parent()
|
||||
if (parent.find('tfoot').length === 0) {
|
||||
parent.append(
|
||||
$('<tfoot></tfoot>')
|
||||
)
|
||||
}
|
||||
const format = Intl.NumberFormat('es-CL', {style: 'currency', currency: 'CLP'})
|
||||
const foot = parent.find('tfoot')
|
||||
foot.html('')
|
||||
const tr = $('<tr></tr>').append(
|
||||
$('<th></th>').attr('colspan', 3).html('<b>Total</b>')
|
||||
)
|
||||
$.each(this.tipos, (i, el) => {
|
||||
tr.append(
|
||||
$('<th></th>').attr('class', 'right aligned').append(
|
||||
$('<b></b>').html(format.format(this.balance[el.descripcion.toLowerCase() + 's']))
|
||||
)
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').html(el.saldoFormateado)
|
||||
)
|
||||
)
|
||||
})
|
||||
foot.append(tr)
|
||||
}
|
||||
}
|
||||
},
|
||||
setup: async function() {
|
||||
this.get().categorias()
|
||||
this.get().tipos_cuentas().then(() => {
|
||||
this.get().tipos_categorias()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
177
ui/public/assets/scripts/tipos_categorias.list.js
Normal file
177
ui/public/assets/scripts/tipos_categorias.list.js
Normal file
@ -0,0 +1,177 @@
|
||||
class TipoCategoria {
|
||||
constructor({id, descripcion, activo}) {
|
||||
this.id = id
|
||||
this.descripcion = descripcion
|
||||
this.activo = activo
|
||||
this.modal = null
|
||||
}
|
||||
setModal(modal) {
|
||||
this.modal = modal
|
||||
}
|
||||
draw() {
|
||||
const chk = $('<input/>').attr('type', 'checkbox').attr('name', 'activo_' + this.id).attr('value', '1')
|
||||
if (this.activo === '1') {
|
||||
chk.parent().addClass('active')
|
||||
chk.attr('checked', 'checked')
|
||||
chk.checkbox('check')
|
||||
}
|
||||
chk.checkbox({
|
||||
onChange: () => {
|
||||
this.changeActivo()
|
||||
}
|
||||
})
|
||||
return $('<tr></tr>').append(
|
||||
$('<td></td>').html(this.descripcion)
|
||||
).append(
|
||||
$('<td></td>').append(
|
||||
$('<div></div>').attr('class', 'ui checkbox').append(chk).append(
|
||||
$('<label></label>').html(' ')
|
||||
)
|
||||
)
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').append(
|
||||
$('<button></button>').attr('class', 'ui tiny circular icon button').attr('data-id', this.id).append(
|
||||
$('<i></i>').attr('class', 'edit icon')
|
||||
).click((e) => {
|
||||
this.edit()
|
||||
})
|
||||
).append(
|
||||
$('<button></button>').attr('class', 'ui tiny circular red icon button').attr('data-id', this.id).append(
|
||||
$('<i></i>').attr('class', 'remove icon')
|
||||
).click((e) => {
|
||||
this.remove()
|
||||
})
|
||||
)
|
||||
)
|
||||
}
|
||||
changeActivo() {
|
||||
const data = JSON.stringify({
|
||||
descripcion: this.descripcion,
|
||||
activo: this.activo === '1' ? 0 : 1
|
||||
})
|
||||
return sendPut(_urls.api + '/tipos/categoria/' + this.id + '/edit', data).then((data) => {
|
||||
this.modal.modal('hide')
|
||||
tipos_categorias.getTipos()
|
||||
})
|
||||
}
|
||||
edit() {
|
||||
const form = this.modal.find('form')
|
||||
form.find("[name='id']").val(this.id)
|
||||
form.find("[name='descripcion']").val(this.descripcion)
|
||||
if (this.activo === '1') {
|
||||
form.find("[name='activo']").attr('checked', 'checked')
|
||||
}
|
||||
modalToEdit(this.modal)
|
||||
this.modal.modal('show')
|
||||
}
|
||||
remove() {
|
||||
sendDelete(_urls.api + '/tipos/categoria/' + this.id + '/delete').then(() => {
|
||||
tipos_categorias.getTipos()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const tipos_categorias = {
|
||||
id: '#tipos_categorias',
|
||||
tipos: [],
|
||||
modal: null,
|
||||
getTipos: function() {
|
||||
this.tipos = []
|
||||
return sendGet(_urls.api + '/tipos/categorias').then((data) => {
|
||||
if (data.tipos === null || data.tipos.length === 0) {
|
||||
return
|
||||
}
|
||||
$.each(data.tipos, (i, el) => {
|
||||
const tipo = new TipoCategoria(el)
|
||||
tipo.setModal(this.modal)
|
||||
this.tipos.push(tipo)
|
||||
})
|
||||
}).then(() => {
|
||||
this.draw()
|
||||
})
|
||||
},
|
||||
getParent: function() {
|
||||
let parent = $(this.id).find('tbody')
|
||||
if (parent.length === 0) {
|
||||
const table = $('<table></table>').attr('class', 'ui table').append(
|
||||
$('<thead></thead>').append(
|
||||
$('<tr></tr>').append(
|
||||
$('<th></th>').attr('class', 'twelve wide').html('Tipo Categoría')
|
||||
).append(
|
||||
$('<th></th>').attr('class', 'two wide').html('Activo')
|
||||
).append(
|
||||
$('<th></th>').attr('class', 'two wide right aligned').append(
|
||||
$('<button></button>').attr('class', 'ui tiny green circular icon button').append(
|
||||
$('<i></i>').attr('class', 'plus icon')
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
table.find('.ui.button').click((e) => {
|
||||
e.preventDefault()
|
||||
this.add()
|
||||
return false
|
||||
})
|
||||
parent = $('<tbody></tbody>')
|
||||
table.append(parent)
|
||||
$(this.id).append(table)
|
||||
}
|
||||
return parent
|
||||
},
|
||||
draw: function() {
|
||||
const parent = this.getParent()
|
||||
parent.html('')
|
||||
$.each(this.tipos, (i, el) => {
|
||||
parent.append(el.draw())
|
||||
})
|
||||
},
|
||||
add: function() {
|
||||
this.modal.find('form').trigger('reset')
|
||||
modalToAdd(this.modal)
|
||||
this.modal.modal('show')
|
||||
},
|
||||
doAdd: function() {
|
||||
const data = JSON.stringify({
|
||||
descripcion: $("[name='descripcion']").val(),
|
||||
activo: $("[name='activo']").val()
|
||||
})
|
||||
return sendPost(_urls.api + '/tipos/categorias/add', data).then((data) => {
|
||||
this.modal.modal('hide')
|
||||
this.getTipos()
|
||||
})
|
||||
},
|
||||
doEdit: function() {
|
||||
const form = this.modal.find('form')
|
||||
const id = form.find("[name='id']").val()
|
||||
const data = JSON.stringify({
|
||||
descripcion: form.find("[name='descripcion']").val(),
|
||||
activo: form.find("[name='activo']").is(':checked') ? 1 : 0
|
||||
})
|
||||
return sendPut(_urls.api + '/tipos/categoria/' + id + '/edit', data).then((data) => {
|
||||
this.modal.modal('hide')
|
||||
this.getTipos()
|
||||
})
|
||||
},
|
||||
setupModal: function() {
|
||||
this.modal = $('.ui.modal')
|
||||
this.modal.modal()
|
||||
this.modal.find('.close.icon').click(() => {
|
||||
this.modal.modal('hide')
|
||||
})
|
||||
this.modal.find('form').submit((e) => {
|
||||
e.preventDefault()
|
||||
const add = $(e.currentTarget).find('.plus.icon')
|
||||
if (add.length > 0) {
|
||||
this.doAdd()
|
||||
} else {
|
||||
this.doEdit()
|
||||
}
|
||||
return false
|
||||
})
|
||||
},
|
||||
setup: function() {
|
||||
this.setupModal()
|
||||
this.getTipos()
|
||||
}
|
||||
}
|
165
ui/public/assets/scripts/tipos_cuentas.list.js
Normal file
165
ui/public/assets/scripts/tipos_cuentas.list.js
Normal file
@ -0,0 +1,165 @@
|
||||
class TipoCuenta {
|
||||
constructor({id, descripcion, color}) {
|
||||
this.id = id
|
||||
this.descripcion = descripcion
|
||||
this.color = color
|
||||
this.modal = null
|
||||
}
|
||||
setModal(modal) {
|
||||
this.modal = modal
|
||||
}
|
||||
setPicker(picker) {
|
||||
this.picker = picker
|
||||
}
|
||||
draw() {
|
||||
return $('<tr></tr>').append(
|
||||
$('<td></td>').append(
|
||||
$('<i></i>').attr('class', 'square full icon').css('color', '#' + this.color)
|
||||
).append(this.descripcion)
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').append(
|
||||
$('<button></button>').attr('class', 'ui tiny circular icon button').attr('data-id', this.id).append(
|
||||
$('<i></i>').attr('class', 'edit icon')
|
||||
).click((e) => {
|
||||
e.preventDefault()
|
||||
this.edit()
|
||||
return false
|
||||
})
|
||||
).append(
|
||||
$('<button></button>').attr('class', 'ui tiny circular red icon button').attr('data-id', this.id).append(
|
||||
$('<i></i>').attr('class', 'remove icon')
|
||||
).click((e) => {
|
||||
e.preventDefault()
|
||||
this.remove()
|
||||
return false
|
||||
})
|
||||
)
|
||||
)
|
||||
}
|
||||
edit() {
|
||||
const form = this.modal.find('form')
|
||||
form.find("[name='id']").val(this.id)
|
||||
form.find("[name='descripcion']").val(this.descripcion)
|
||||
form.find("[name='color']").val(this.color)
|
||||
this.picker.setColor(this.color)
|
||||
modalToEdit(this.modal)
|
||||
this.modal.modal('show')
|
||||
}
|
||||
remove() {
|
||||
sendDelete(_urls.api + '/tipos/cuenta/' + this.id + '/delete').then(() => {
|
||||
tipos_cuentas.getTipos()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const tipos_cuentas = {
|
||||
id: '#tipos_cuentas',
|
||||
tipos: [],
|
||||
getTipos: function() {
|
||||
this.tipos = []
|
||||
return sendGet(_urls.api + '/tipos/cuentas').then((data) => {
|
||||
if (data.tipos === null || data.tipos.length === 0) {
|
||||
return
|
||||
}
|
||||
$.each(data.tipos, (i, el) => {
|
||||
const tipo = new TipoCuenta(el)
|
||||
tipo.setModal(this.modal)
|
||||
tipo.setPicker(this.picker)
|
||||
this.tipos.push(tipo)
|
||||
})
|
||||
}).then(() => {
|
||||
this.draw()
|
||||
})
|
||||
},
|
||||
buildParent: function(segment) {
|
||||
const table = $('<table></table>').attr('class', 'ui table').append(
|
||||
$('<thead></thead>').append(
|
||||
$('<tr></tr>').append(
|
||||
$('<th></th>').html('Tipo')
|
||||
).append(
|
||||
$('<th></th>').attr('class', 'right aligned').append(
|
||||
$('<button></button>').attr('class', 'ui tiny green circular icon button').append(
|
||||
$('<i></i>').attr('class', 'plus icon')
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
table.find('.ui.button').click((e) => {
|
||||
e.preventDefault()
|
||||
this.add()
|
||||
return false
|
||||
})
|
||||
parent = $('<tbody></tbody>')
|
||||
table.append(parent)
|
||||
segment.append(table)
|
||||
return parent
|
||||
},
|
||||
getParent: function() {
|
||||
const segment = $(this.id)
|
||||
let parent = segment.find('tbody')
|
||||
if (parent.length === 0) {
|
||||
parent = this.buildParent(segment)
|
||||
}
|
||||
return parent
|
||||
},
|
||||
draw: function() {
|
||||
const parent = this.getParent()
|
||||
parent.html('')
|
||||
$.each(this.tipos, (i, el) => {
|
||||
parent.append(el.draw())
|
||||
})
|
||||
},
|
||||
add: function() {
|
||||
this.modal.find('form').trigger('reset')
|
||||
this.picker.setColor('ffffff')
|
||||
modalToAdd(this.modal)
|
||||
this.modal.modal('show')
|
||||
},
|
||||
doAdd: function() {
|
||||
const data = JSON.stringify({
|
||||
descripcion: this.modal.find('form').find("[name='descripcion']").val(),
|
||||
color: this.modal.find('form').find("[name='color']").val()
|
||||
})
|
||||
return sendPost(
|
||||
_urls.api + '/tipos/cuentas/add',
|
||||
data
|
||||
).then((data) => {
|
||||
this.modal.modal('hide')
|
||||
this.getCuentas()
|
||||
})
|
||||
},
|
||||
doEdit: function() {
|
||||
id = this.modal.find('form').find("[name='id']").val()
|
||||
const data = JSON.stringify({
|
||||
descripcion: this.modal.find('form').find("[name='descripcion']").val(),
|
||||
color: this.modal.find('form').find("[name='color']").val()
|
||||
})
|
||||
sendPut(_urls.api + '/tipos/cuenta/' + id + '/edit', data).then((data) => {
|
||||
this.modal.modal('hide')
|
||||
this.getTipos()
|
||||
})
|
||||
},
|
||||
setupModal: function() {
|
||||
this.modal = $('.ui.modal')
|
||||
this.modal.modal()
|
||||
this.modal.find('.close.icon').css('cursor', 'pointer').click(() => {
|
||||
this.modal.modal('hide')
|
||||
})
|
||||
this.picker = new ColorPicker(this.modal.find("[name='color']"))
|
||||
this.modal.find('form').submit((e) => {
|
||||
e.preventDefault()
|
||||
const add = $(e.currentTarget).find('.add.icon')
|
||||
if (add.length > 0) {
|
||||
this.doAdd()
|
||||
} else {
|
||||
this.doEdit()
|
||||
}
|
||||
return false
|
||||
})
|
||||
},
|
||||
setup: function() {
|
||||
this.setupModal()
|
||||
this.getTipos()
|
||||
}
|
||||
}
|
4
ui/resources/routes/config.php
Normal file
4
ui/resources/routes/config.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Config;
|
||||
|
||||
$app->get('/config', Config::class);
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Home;
|
||||
|
||||
$app->get('/info[/]', [Home::class, 'info']);
|
||||
$app->get('[/]', Home::class);
|
||||
|
13
ui/resources/routes/tipos.php
Normal file
13
ui/resources/routes/tipos.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
$folder = implode(DIRECTORY_SEPARATOR, [__DIR__, 'tipos']);
|
||||
if (file_exists($folder)) {
|
||||
$app->group('/tipos', function($app) use ($folder) {
|
||||
$files = new DirectoryIterator($folder);
|
||||
foreach ($files as $file) {
|
||||
if ($file->isDir() or $file->getExtension() != 'php') {
|
||||
continue;
|
||||
}
|
||||
include_once $file->getRealPath();
|
||||
}
|
||||
});
|
||||
}
|
4
ui/resources/routes/tipos/tipos_categorias.php
Normal file
4
ui/resources/routes/tipos/tipos_categorias.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\TiposCategorias;
|
||||
|
||||
$app->get('/categorias', TiposCategorias::class);
|
4
ui/resources/routes/tipos/tipos_cuentas.php
Normal file
4
ui/resources/routes/tipos/tipos_cuentas.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\TiposCuentas;
|
||||
|
||||
$app->get('/cuentas', TiposCuentas::class);
|
@ -6,10 +6,19 @@
|
||||
<i class="close icon"></i>
|
||||
<div class="content">
|
||||
<form class="ui form">
|
||||
<input type="hidden" name="id" />
|
||||
<div class="field">
|
||||
<label>Nombre</label>
|
||||
<input type="text" name="nombre" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Tipo</label>
|
||||
<div class="ui selection dropdown" id="tipos">
|
||||
<input type="hidden" name="tipo" />
|
||||
<div class="default text">Tipo</div>
|
||||
<div class="menu"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui icon button">
|
||||
<i class="plus icon"></i>
|
||||
</button>
|
||||
|
14
ui/resources/views/categorias/tipos/base.blade.php
Normal file
14
ui/resources/views/categorias/tipos/base.blade.php
Normal file
@ -0,0 +1,14 @@
|
||||
@extends('config.base')
|
||||
|
||||
@section('config_content')
|
||||
<h1 class="ui header">
|
||||
@hasSection('tipos_categorias_title')
|
||||
Tipo Categoría @yield('tipos_categorias_title')
|
||||
@else
|
||||
Tipos Categoría
|
||||
@endif
|
||||
</h1>
|
||||
<div class="ui segment">
|
||||
@yield('tipos_categorias_content')
|
||||
</div>
|
||||
@endsection
|
33
ui/resources/views/categorias/tipos/list.blade.php
Normal file
33
ui/resources/views/categorias/tipos/list.blade.php
Normal file
@ -0,0 +1,33 @@
|
||||
@extends('categorias.tipos.base')
|
||||
|
||||
@section('tipos_categorias_content')
|
||||
<div id="tipos_categorias"></div>
|
||||
<div class="ui modal">
|
||||
<i class="close icon"></i>
|
||||
<div class="content">
|
||||
<form class="ui form">
|
||||
<input type="hidden" name="id" />
|
||||
<div class="field">
|
||||
<label>Descripción</label>
|
||||
<input type="text" name="descripcion" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Activo</label>
|
||||
<input type="checkbox" name="activo" value="1" />
|
||||
</div>
|
||||
<button class="ui icon button">
|
||||
<i class="plus icon"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script type="text/javascript" src="{{$urls->scripts}}/tipos_categorias.list.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(() => {
|
||||
tipos_categorias.setup()
|
||||
})
|
||||
</script>
|
||||
@endpush
|
20
ui/resources/views/config/base.blade.php
Normal file
20
ui/resources/views/config/base.blade.php
Normal file
@ -0,0 +1,20 @@
|
||||
@extends('layout.base')
|
||||
|
||||
@section('page_content')
|
||||
<h1 class="ui header">
|
||||
@hasSection('config_title')
|
||||
@yield('config_title')
|
||||
@else
|
||||
Configuraciones
|
||||
@endif
|
||||
</h1>
|
||||
<div class="ui compact grid">
|
||||
<div class="three wide column">
|
||||
@include('config.menu')
|
||||
</div>
|
||||
<div class="thirteen wide column">
|
||||
<div class="ui segment">
|
||||
@yield('config_content')
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
1
ui/resources/views/config/list.blade.php
Normal file
1
ui/resources/views/config/list.blade.php
Normal file
@ -0,0 +1 @@
|
||||
@extends('config.base')
|
4
ui/resources/views/config/menu.blade.php
Normal file
4
ui/resources/views/config/menu.blade.php
Normal file
@ -0,0 +1,4 @@
|
||||
<div class="ui vertical fluid borderless menu">
|
||||
@include('config.menu.tipos_categorias')
|
||||
@include('config.menu.tipos_cuentas')
|
||||
</div>
|
@ -0,0 +1,3 @@
|
||||
<a class="item" href="{{$urls->base}}tipos/categorias">
|
||||
Tipos Categorías
|
||||
</a>
|
3
ui/resources/views/config/menu/tipos_cuentas.blade.php
Normal file
3
ui/resources/views/config/menu/tipos_cuentas.blade.php
Normal file
@ -0,0 +1,3 @@
|
||||
<a class="item" href="{{$urls->base}}tipos/cuentas">
|
||||
Tipos Cuentas
|
||||
</a>
|
@ -6,6 +6,7 @@
|
||||
<i class="close icon"></i>
|
||||
<div class="content">
|
||||
<form class="ui form">
|
||||
<input type="hidden" name="id" />
|
||||
<div class="inline field">
|
||||
<label>Categoría</label>
|
||||
<select name="categoria"></select>
|
||||
@ -14,6 +15,14 @@
|
||||
<label>Nombre</label>
|
||||
<input type="text" name="nombre" />
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<label>Tipo</label>
|
||||
<select name="tipo"></select>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<label>Moneda</label>
|
||||
<select name="moneda"></select>
|
||||
</div>
|
||||
<button class="ui icon button">
|
||||
<i class="plus icon"></i>
|
||||
</button>
|
||||
|
@ -50,6 +50,7 @@
|
||||
<i class="close icon"></i>
|
||||
<div class="content">
|
||||
<form class="ui form">
|
||||
<input type="hidden" name="id" />
|
||||
<div class="field">
|
||||
<label>Fecha</label>
|
||||
<div class="ui calendar">
|
||||
|
14
ui/resources/views/cuentas/tipos/base.blade.php
Normal file
14
ui/resources/views/cuentas/tipos/base.blade.php
Normal file
@ -0,0 +1,14 @@
|
||||
@extends('config.base')
|
||||
|
||||
@section('config_content')
|
||||
<h1 class="ui header">
|
||||
@hasSection('tipos_cuentas_title')
|
||||
Tipo Cuenta @yield('tipos_cuentas_title')
|
||||
@else
|
||||
Tipos Cuenta
|
||||
@endif
|
||||
</h1>
|
||||
<div class="ui basic fitted segment">
|
||||
@yield('tipos_cuentas_content')
|
||||
</div>
|
||||
@endsection
|
34
ui/resources/views/cuentas/tipos/list.blade.php
Normal file
34
ui/resources/views/cuentas/tipos/list.blade.php
Normal file
@ -0,0 +1,34 @@
|
||||
@extends('cuentas.tipos.base')
|
||||
|
||||
@section('tipos_cuentas_content')
|
||||
<div id="tipos_cuentas"></div>
|
||||
<div class="ui modal">
|
||||
<i class="close icon"></i>
|
||||
<div class="content">
|
||||
<form class="ui form">
|
||||
<input type="hidden" name="id" />
|
||||
<div class="field">
|
||||
<label>Descripcion</label>
|
||||
<input type="text" name="descripcion" />
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<lable>Color</lable>
|
||||
<input type="text" name="color" value="ffffff" />
|
||||
</div>
|
||||
<button class="ui icon button">
|
||||
<i class="plus icon"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script type="text/javascript" src="{{$urls->scripts}}/colorpicker.js"></script>
|
||||
<script type="text/javascript" src="{{$urls->scripts}}/tipos_cuentas.list.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(() => {
|
||||
tipos_cuentas.setup()
|
||||
})
|
||||
</script>
|
||||
@endpush
|
2
ui/resources/views/info.blade.php
Normal file
2
ui/resources/views/info.blade.php
Normal file
@ -0,0 +1,2 @@
|
||||
<?php
|
||||
phpinfo();
|
@ -2,4 +2,7 @@
|
||||
<a class="item" href="{{$urls->base}}">Inicio</a>
|
||||
@include('layout.body.menu.cuentas')
|
||||
@include('layout.body.menu.categorias')
|
||||
<div class="right menu">
|
||||
<a class="item" href="{{$urls->base}}config">Config</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
@ -2,10 +2,45 @@
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.8.8/semantic.min.js" integrity="sha512-t5mAtfZZmR2gl5LK7WEkJoyHCfyzoy10MlerMGhxsXl3J7uSSNTAW6FK/wvGBC8ua9AFazwMaC0LxsMTMiM5gg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
const API_KEY = '{{$api_key}}'
|
||||
const _urls = {
|
||||
base: '{{$urls->base}}',
|
||||
api: '{{$urls->api}}'
|
||||
}
|
||||
function buildAjax(url, method) {
|
||||
return {
|
||||
url: url,
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + API_KEY
|
||||
},
|
||||
method: method,
|
||||
dataType: 'json'
|
||||
}
|
||||
}
|
||||
function sendGet(url) {
|
||||
let ajax_obj = buildAjax(url, 'GET')
|
||||
return $.ajax(ajax_obj)
|
||||
}
|
||||
function sendPost(url, data) {
|
||||
let ajax_obj = buildAjax(url, 'POST')
|
||||
ajax_obj['data'] = data
|
||||
return $.ajax(ajax_obj)
|
||||
}
|
||||
function sendPut(url, data) {
|
||||
let ajax_obj = buildAjax(url, 'PUT')
|
||||
ajax_obj['data'] = data
|
||||
return $.ajax(ajax_obj)
|
||||
}
|
||||
function sendDelete(url) {
|
||||
let ajax_obj = buildAjax(url, 'DELETE')
|
||||
return $.ajax(ajax_obj)
|
||||
}
|
||||
function modalToEdit(modal) {
|
||||
$(modal).find('form').find('button').find('.icon').attr('class', 'edit icon')
|
||||
}
|
||||
function modalToAdd(modal) {
|
||||
$(modal).find('form').find('button').find('.icon').attr('class', 'plus icon')
|
||||
}
|
||||
</script>
|
||||
|
||||
@stack('scripts')
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
return [
|
||||
'debug' => $_ENV['DEBUG'] ?? false
|
||||
'debug' => $_ENV['DEBUG'] ?? false,
|
||||
'API_KEY' => $_ENV['API_KEY'] ?? ''
|
||||
];
|
||||
|
@ -16,6 +16,10 @@ return [
|
||||
$arr['assets'],
|
||||
'scripts'
|
||||
]);
|
||||
$arr['styles'] = implode('/', [
|
||||
$arr['assets'],
|
||||
'styles'
|
||||
]);
|
||||
$arr['api'] = $_ENV['API_URL'] ?? 'http://localhost:9001';
|
||||
return (object) $arr;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ return [
|
||||
$c->get('folders')->cache,
|
||||
null,
|
||||
[
|
||||
'api_key' => $c->get('API_KEY'),
|
||||
'urls' => $c->get('urls')
|
||||
]
|
||||
);
|
||||
|
@ -1,12 +0,0 @@
|
||||
from threading import Thread
|
||||
import httpx
|
||||
|
||||
|
||||
class Worker(Thread):
|
||||
def __init__(self, settings):
|
||||
self.settings = settings
|
||||
|
||||
def run():
|
||||
while True:
|
||||
if self.stop_event.isSet():
|
||||
break
|
Reference in New Issue
Block a user