Compare commits
14 Commits
python
...
430e29eaec
Author | SHA1 | Date | |
---|---|---|---|
430e29eaec | |||
79c7d5ad63 | |||
e6ebb2c279 | |||
45952bb3ac | |||
6b03d62ce0 | |||
894cc26b21 | |||
64ffb53f0c | |||
42310ef0e4 | |||
a6362a6770 | |||
e9c63abc3a | |||
9f47c8a85f | |||
34eedb93d7 | |||
0e5714edc8 | |||
f33bddfbea |
@ -1,3 +1,4 @@
|
||||
COMPOSE_PROFILES=
|
||||
MYSQL_HOST=
|
||||
MYSQL_ROOT_PASSWORD=
|
||||
MYSQL_DATABASE=
|
||||
|
@ -24,4 +24,11 @@ class Base {
|
||||
$key = urlencode(base64_encode($signature));
|
||||
return $this->withJson($response, ['key' => $key]);
|
||||
}
|
||||
public function info(Request $request, Response $response): Response {
|
||||
ob_start();
|
||||
phpinfo();
|
||||
$data = ob_get_clean();
|
||||
$response->getBody()->write($data);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
@ -13,33 +13,35 @@ class Categorias {
|
||||
|
||||
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;
|
||||
if ($categorias !== null) {
|
||||
array_walk($categorias, function(&$item) use ($service) {
|
||||
$arr = $item->toArray();
|
||||
if ($item->cuentas()) {
|
||||
$arr['cuentas'] = array_map(function($item) {
|
||||
return $item->toArray();
|
||||
}, $item->cuentas());
|
||||
}
|
||||
$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']);
|
||||
});
|
||||
$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;
|
||||
});
|
||||
usort($categorias, function($a, $b) {
|
||||
return strcmp($a['nombre'], $b['nombre']);
|
||||
});
|
||||
}
|
||||
$output = [
|
||||
'categorias' => $categorias
|
||||
'categorias' => $categorias
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
|
@ -12,8 +12,13 @@ class Cuentas {
|
||||
use Json;
|
||||
|
||||
public function __invoke(Request $request, Response $response, Factory $factory): Response {
|
||||
$cuentas = $factory->find(Cuenta::class)->array();
|
||||
$cuentas = $factory->find(Cuenta::class)->many();
|
||||
if ($cuentas) {
|
||||
array_walk($cuentas, function (&$item) {
|
||||
$arr = $item->toArray();
|
||||
$arr['categoria'] = $item->categoria()->toArray();
|
||||
$item = $arr;
|
||||
});
|
||||
usort($cuentas, function($a, $b) {
|
||||
$t = strcmp($a['tipo']['descripcion'], $b['tipo']['descripcion']);
|
||||
if ($t != 0) {
|
||||
|
@ -3,19 +3,47 @@ namespace Contabilidad\Common\Controller;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Container\ContainerInterface as Container;
|
||||
use ProVM\Common\Define\Controller\Json;
|
||||
use ProVM\Common\Factory\Model as Factory;
|
||||
use Contabilidad\Common\Service\DocumentHandler as Handler;
|
||||
use Contabilidad\Cuenta;
|
||||
|
||||
class Import {
|
||||
use Json;
|
||||
|
||||
public function __invoke(Request $request, Response $response, Factory $factory): Response {
|
||||
$post = $request->getParsedBody();
|
||||
return $this->withJson($response, $post);
|
||||
public function __invoke(Request $request, Response $response, Factory $factory, Container $container): Response {
|
||||
$post =$request->getParsedBody();
|
||||
$cuenta = $factory->find(Cuenta::class)->one($post['cuenta']);
|
||||
$file = $request->getUploadedFiles()['archivo'];
|
||||
$valid_media = [
|
||||
'text/csv' => 'csvs',
|
||||
'application/pdf' => 'pdfs',
|
||||
'application/vnd.ms-excel' => 'xlss',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'xlss',
|
||||
'application/json' => 'jsons'
|
||||
];
|
||||
if ($file->getError() === 0 and in_array($file->getClientMediaType(), array_keys($valid_media))) {
|
||||
$filenfo = new \SplFileInfo($file->getClientFilename());
|
||||
$new_name = implode('.', [implode(' - ', [$cuenta->nombre, $cuenta->categoria()->nombre, $post['fecha']]), $filenfo->getExtension()]);
|
||||
$to = implode(DIRECTORY_SEPARATOR, [$container->get('folders')->uploads, $valid_media[$file->getClientMediaType()], $new_name]);
|
||||
$file->moveTo($to);
|
||||
$status = file_exists($to);
|
||||
}
|
||||
$output = [
|
||||
'input' => [
|
||||
'name' => $file->getClientFilename(),
|
||||
'type' => $file->getClientMediaType(),
|
||||
'size' => $file->getSize(),
|
||||
'error' => $file->getError()
|
||||
],
|
||||
'new_name' => $new_name,
|
||||
'uploaded' => $status
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function uploads(Request $request, Response $response, Handler $handler): Response {
|
||||
$output = $handler->handle();
|
||||
return $this->withJson($response, $output);
|
||||
$output = $handler->handle();
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
}
|
||||
|
@ -13,31 +13,34 @@ class TiposCategorias {
|
||||
|
||||
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;
|
||||
if ($tipos !== null) {
|
||||
array_walk($tipos, function(&$item) use ($service) {
|
||||
$arr = $item->toArray();
|
||||
$arr['categorias'] = $item->categorias();
|
||||
if ($arr['categorias'] !== null) {
|
||||
$arr['categorias'] = array_map(function($item) {
|
||||
return $item->toArray();
|
||||
}, $item->categorias());
|
||||
}
|
||||
$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']);
|
||||
});
|
||||
$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;
|
||||
});
|
||||
usort($tipos, function($a, $b) {
|
||||
return strcmp($a['descripcion'], $b['descripcion']);
|
||||
});
|
||||
}
|
||||
$output = [
|
||||
'tipos' => $tipos
|
||||
|
@ -20,7 +20,7 @@ final class TipoCuenta extends AbstractMigration
|
||||
{
|
||||
$this->table('tipos_cuenta')
|
||||
->addColumn('descripcion', 'string')
|
||||
->addColumn('color', 'string', ['length' => 6])
|
||||
->addColumn('color', 'string', ['length' => 6, 'default' => 'ffffff'])
|
||||
->create();
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ server {
|
||||
access_log /var/log/nginx/access.log;
|
||||
root /app/public;
|
||||
|
||||
client_max_body_size 50M;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
@ -1,2 +1,4 @@
|
||||
log_errors = true
|
||||
error_log = /var/log/php/error.log
|
||||
error_log = /var/log/php/error.log
|
||||
upload_max_filesize = 50M
|
||||
max_input_vars = 5000
|
||||
|
@ -3,4 +3,5 @@ use Contabilidad\Common\Controller\Base;
|
||||
|
||||
$app->get('/key/generate[/]', [Base::class, 'generate_key']);
|
||||
$app->get('/balance[/]', [Contabilidad\Common\Controller\TiposCategorias::class, 'balance']);
|
||||
$app->get('/info', [Base::class, 'info']);
|
||||
$app->get('/', Base::class);
|
||||
|
@ -2,9 +2,9 @@
|
||||
use Psr\Container\ContainerInterface as Container;
|
||||
|
||||
return [
|
||||
GuzzleHttp\Client::class => function(Container $c) {
|
||||
return new GuzzleHttp\Client();
|
||||
},
|
||||
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'));
|
||||
},
|
||||
|
@ -89,4 +89,10 @@ class Categoria extends Model {
|
||||
}
|
||||
return $this->saldo;
|
||||
}
|
||||
|
||||
public function toArray(): array {
|
||||
$arr = parent::toArray();
|
||||
$arr['tipo'] = $this->tipo()->toArray();
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
|
@ -10,20 +10,20 @@ use Contabilidad\Common\Service\TiposCambios as Service;
|
||||
* @property int $activo
|
||||
*/
|
||||
class TipoCategoria extends Model {
|
||||
public static $_table = 'tipos_categoria';
|
||||
protected static $fields = ['descripcion', 'activo'];
|
||||
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']);
|
||||
protected $categorias;
|
||||
public function categorias() {
|
||||
if ($this->categorias === null) {
|
||||
$this->categorias = $this->parentOf(Categoria::class, [Model::CHILD_KEY => 'tipo_id']);
|
||||
}
|
||||
return $this->categorias;
|
||||
}
|
||||
return $this->categorias;
|
||||
}
|
||||
|
||||
public function getCuentasOf($tipo) {
|
||||
return $this->factory->find(Cuenta::class)
|
||||
->select([['cuentas', '*']])
|
||||
->select('cuentas.*')
|
||||
->join([
|
||||
['tipos_cuenta', 'tipos_cuenta.id', 'cuentas.tipo_id'],
|
||||
['categorias', 'categorias.id', 'cuentas.categoria_id']
|
||||
@ -37,7 +37,7 @@ class TipoCategoria extends Model {
|
||||
protected $saldo;
|
||||
public function saldo(Service $service = null) {
|
||||
if ($this->saldo === null) {
|
||||
$this->saldo = array_reduce($this->categorias(), function($sum, $item) use ($service) {
|
||||
$this->saldo = array_reduce($this->categorias() ?? [], function($sum, $item) use ($service) {
|
||||
return $sum + $item->saldo($service);
|
||||
});
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ services:
|
||||
image: php-ui
|
||||
env_file:
|
||||
- .api.env
|
||||
- .env
|
||||
build:
|
||||
context: ui
|
||||
volumes:
|
||||
|
@ -1,3 +1,5 @@
|
||||
FROM php:8-fpm
|
||||
|
||||
COPY --from=composer /usr/bin/composer /usr/bin/composer
|
||||
|
||||
WORKDIR /app
|
||||
|
12
ui/common/Controller/Importar.php
Normal file
12
ui/common/Controller/Importar.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 Importar {
|
||||
public function __invoke(Request $request, Response $response, View $view): Response {
|
||||
return $view->render($response, 'importar');
|
||||
}
|
||||
}
|
4
ui/resources/routes/importar.php
Normal file
4
ui/resources/routes/importar.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Importar;
|
||||
|
||||
$app->get('/importar[/]', Importar::class);
|
92
ui/resources/views/importar.blade.php
Normal file
92
ui/resources/views/importar.blade.php
Normal file
@ -0,0 +1,92 @@
|
||||
@extends('layout.base')
|
||||
|
||||
@section('page_title')
|
||||
Importar
|
||||
@endsection
|
||||
|
||||
@section('page_content')
|
||||
<h1>Importar</h1>
|
||||
<form class="ui form" action="#" method="post" id="importar_form" enctype="multipart/form-data">
|
||||
<div class="two wide field">
|
||||
<label>Fecha</label>
|
||||
<div class="ui date calendar">
|
||||
<div class="ui icon input">
|
||||
<input type="text" name="fecha" />
|
||||
<i class="calendar outline icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="six wide field">
|
||||
<label>Cuenta</label>
|
||||
<select name="cuenta"></select>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<input type="file" name="archivo" style="display: none;" />
|
||||
<div class="ui labeled icon input" id="archivo_btn">
|
||||
<div class="ui label">Archivo</div>
|
||||
<input type="text" readonly="" />
|
||||
<i class="search icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui button">Importar</button>
|
||||
</form>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script type="text/javascript">
|
||||
function getCuentas() {
|
||||
sendGet(_urls.api + '/cuentas').then((data) => {
|
||||
if (data.cuentas === null || data.cuentas.length === 0) {
|
||||
return
|
||||
}
|
||||
const select = $("select[name='cuenta']")
|
||||
let values = []
|
||||
$.each(data.cuentas, (i, el) => {
|
||||
const nombre = [el.nombre, el.categoria.nombre].join(' - ')
|
||||
values.push({
|
||||
name: nombre,
|
||||
value: el.id,
|
||||
text: nombre
|
||||
})
|
||||
})
|
||||
select.dropdown({values})
|
||||
})
|
||||
}
|
||||
$(document).ready(() => {
|
||||
getCuentas()
|
||||
const today = new Date()
|
||||
const start = new Date(today.getFullYear(), today.getMonth() - 1)
|
||||
$('.ui.calendar').calendar({
|
||||
type: 'month',
|
||||
initialDate: start,
|
||||
maxDate: start,
|
||||
months: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'],
|
||||
monthsShort: ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'],
|
||||
formatter: {
|
||||
date: function(date, settings) {
|
||||
if (!date) return ''
|
||||
const year = date.getFullYear()
|
||||
const month = date.getMonth() + 1
|
||||
return [year, month].join('-')
|
||||
}
|
||||
}
|
||||
})
|
||||
$('#archivo_btn').css('cursor', 'pointer').click(() => {
|
||||
$("[name='archivo']").trigger('click')
|
||||
})
|
||||
$("[name='archivo']").change((e) => {
|
||||
const arch = $(e.currentTarget)
|
||||
const filename = arch[0].files[0].name
|
||||
$('#archivo_btn').find('input').val(filename)
|
||||
})
|
||||
$('#importar_form').submit((e) => {
|
||||
e.preventDefault()
|
||||
const data = new FormData(e.currentTarget)
|
||||
sendPost(_urls.api + '/import', data, true).then((resp) => {
|
||||
console.debug(resp)
|
||||
})
|
||||
return false
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@endpush
|
@ -2,6 +2,7 @@
|
||||
<a class="item" href="{{$urls->base}}">Inicio</a>
|
||||
@include('layout.body.menu.cuentas')
|
||||
@include('layout.body.menu.categorias')
|
||||
<a class="item" href="{{$urls->base}}importar">Importar</a>
|
||||
<div class="right menu">
|
||||
<a class="item" href="{{$urls->base}}config">Config</a>
|
||||
</div>
|
||||
|
@ -7,7 +7,18 @@
|
||||
base: '{{$urls->base}}',
|
||||
api: '{{$urls->api}}'
|
||||
}
|
||||
function buildAjax(url, method) {
|
||||
function buildAjax(url, method, files=false) {
|
||||
if (files) {
|
||||
return {
|
||||
url: url,
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + API_KEY
|
||||
},
|
||||
method: method,
|
||||
processData: false,
|
||||
contentType: false
|
||||
}
|
||||
}
|
||||
return {
|
||||
url: url,
|
||||
headers: {
|
||||
@ -21,8 +32,8 @@
|
||||
let ajax_obj = buildAjax(url, 'GET')
|
||||
return $.ajax(ajax_obj)
|
||||
}
|
||||
function sendPost(url, data) {
|
||||
let ajax_obj = buildAjax(url, 'POST')
|
||||
function sendPost(url, data, files=false) {
|
||||
let ajax_obj = buildAjax(url, 'POST', files)
|
||||
ajax_obj['data'] = data
|
||||
return $.ajax(ajax_obj)
|
||||
}
|
||||
|
Reference in New Issue
Block a user