Merge branch 'develop' into release

This commit is contained in:
2021-12-20 22:54:14 -03:00
17 changed files with 238 additions and 72 deletions

View File

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

View File

@ -13,35 +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();
if ($item->cuentas()) {
$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);
}

View File

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

View File

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

View File

@ -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();
}
}

View File

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

View File

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

View File

@ -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);

View File

@ -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'));
},

View File

@ -10,16 +10,16 @@ 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)
@ -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);
});
}

View File

@ -50,6 +50,7 @@ services:
image: php-ui
env_file:
- .api.env
- .env
build:
context: ui
volumes:

View File

@ -1,3 +1,5 @@
FROM php:8-fpm
COPY --from=composer /usr/bin/composer /usr/bin/composer
WORKDIR /app

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

View File

@ -0,0 +1,4 @@
<?php
use Contabilidad\Common\Controller\Importar;
$app->get('/importar[/]', Importar::class);

View 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

View File

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

View File

@ -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)
}