Compare commits
36 Commits
f36399c1f4
...
release
Author | SHA1 | Date | |
---|---|---|---|
459a95bf12 | |||
06071884c7 | |||
ca8229abee | |||
6ff584013f | |||
cf27465d75 | |||
560fb356fa | |||
6c4e51bfff | |||
10e5383a3e | |||
81ff87d355 | |||
bc5338b1f1 | |||
4db8161c70 | |||
d94f076946 | |||
899e9f6070 | |||
8009433958 | |||
d7b406ef25 | |||
cddf768b1e | |||
0bd54fa8a4 | |||
8b86560973 | |||
f6285d6970 | |||
4ea5c6de3e | |||
5f4f5d1501 | |||
91cc28e681 | |||
ef01ab3c55 | |||
e41ffd505b | |||
0e7d7200b6 | |||
2986806137 | |||
f9076d3bac | |||
ee3133da72 | |||
dbad283e14 | |||
e3737aba27 | |||
fcc84ac09c | |||
d0d123e12e | |||
2b3b475d91 | |||
e5cf3cfa07 | |||
71975ec6d9 | |||
84a3f8e2e3 |
1
.console.env.sample
Normal file
1
.console.env.sample
Normal file
@ -0,0 +1 @@
|
||||
API_URL=http://api-proxy
|
5
.db.env.sample
Normal file
5
.db.env.sample
Normal file
@ -0,0 +1,5 @@
|
||||
MYSQL_HOST=
|
||||
MYSQL_ROOT_PASSWORD=
|
||||
MYSQL_DATABASE=
|
||||
MYSQL_USER=
|
||||
MYSQL_PASSWORD=
|
@ -1,6 +1 @@
|
||||
COMPOSE_PROFILES=
|
||||
MYSQL_HOST=
|
||||
MYSQL_ROOT_PASSWORD=
|
||||
MYSQL_DATABASE=
|
||||
MYSQL_USER=
|
||||
MYSQL_PASSWORD=
|
||||
|
66
api/common/Controller/Consolidados.php
Normal file
66
api/common/Controller/Consolidados.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?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\Factory\Model as Factory;
|
||||
use ProVM\Common\Define\Controller\Json;
|
||||
use Contabilidad\Common\Service\Consolidar as Service;
|
||||
use Contabilidad\Cuenta;
|
||||
use Contabilidad\Consolidado;
|
||||
|
||||
class Consolidados {
|
||||
use Json;
|
||||
|
||||
public function __invoke(Request $request, Response $response, Factory $factory, $cuenta_id): Response {
|
||||
$consolidados = $factory->find(Consolidados::class)->where([['cuenta_id' => $cuenta_id]])->many();
|
||||
$output = [
|
||||
'consolidados' => array_map(function($item) {
|
||||
return $item->toArray();
|
||||
}, $consolidados)
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function add(Request $request, Response $response, Factory $factory): Response {
|
||||
$input = json_decode($request->getBody()->getContents());
|
||||
$output = [
|
||||
'input' => $input,
|
||||
'consolidados' => []
|
||||
];
|
||||
if (!is_array($input)) {
|
||||
$input = [$input];
|
||||
}
|
||||
foreach ($input as $data) {
|
||||
$consolidado = Consolidado::add($factory, $data);
|
||||
$status = $consolidado->save();
|
||||
$output['consolidados'] []= [
|
||||
'consolidado' => $consolidado->toArray(),
|
||||
'added' => $status
|
||||
];
|
||||
}
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function cli(Request $request, Response $response, Service $service): Response {
|
||||
try {
|
||||
if (!$service->isConsolidado()) {
|
||||
$service->consolidar();
|
||||
}
|
||||
} catch (\Error | \Exception $e) {
|
||||
error_log($e);
|
||||
throw $e;
|
||||
}
|
||||
return $this->withJson($response, []);
|
||||
}
|
||||
public function update(Request $request, Response $response, Factory $factory, Service $service, $mes, $cuenta_id): Response {
|
||||
try {
|
||||
$cuenta = $factory->find(Cuenta::class)->one($cuenta_id);
|
||||
$mes = Carbon::parse($mes);
|
||||
$service->consolidarCuenta($cuenta, $mes);
|
||||
} catch (\Error | \Exception $e) {
|
||||
error_log($e);
|
||||
throw $e;
|
||||
}
|
||||
return $this->withJson($response, []);
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Controller;
|
||||
|
||||
use Contabilidad\Transaccion;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Carbon\Carbon;
|
||||
use ProVM\Common\Define\Controller\Json;
|
||||
use ProVM\Common\Factory\Model as Factory;
|
||||
use Contabilidad\Common\Service\TiposCambios as Service;
|
||||
@ -109,6 +111,24 @@ class Cuentas {
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
protected function transaccionToArray(Service $service, Cuenta $cuenta, Transaccion $transaccion): array {
|
||||
$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'] = $transaccion->valor;
|
||||
$arr['valorFormateado'] = $cuenta->moneda()->format($arr['valor']);
|
||||
}
|
||||
}
|
||||
$arr['debito']['categoria'] = $transaccion->debito()->categoria()->toArray();
|
||||
$arr['credito']['categoria'] = $transaccion->credito()->categoria()->toArray();
|
||||
return $arr;
|
||||
}
|
||||
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;
|
||||
@ -116,22 +136,7 @@ class Cuentas {
|
||||
$transacciones = $cuenta->transacciones($limit, $start);
|
||||
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']);
|
||||
}
|
||||
}
|
||||
$arr['debito']['categoria'] = $transaccion->debito()->categoria()->toArray();
|
||||
$arr['credito']['categoria'] = $transaccion->credito()->categoria()->toArray();
|
||||
$transaccion = $arr;
|
||||
$transaccion = $this->transaccionToArray($service, $cuenta, $transaccion);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -142,6 +147,40 @@ class Cuentas {
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function transaccionesMonth(Request $request, Response $response, Factory $factory, Service $service, $cuenta_id, $month): Response {
|
||||
$cuenta = $factory->find(Cuenta::class)->one($cuenta_id);
|
||||
$month = Carbon::parse($month);
|
||||
$transacciones = null;
|
||||
if ($cuenta !== null) {
|
||||
$transacciones = $cuenta->transaccionesMonth($month);
|
||||
if (count($transacciones) > 0) {
|
||||
foreach ($transacciones as &$transaccion) {
|
||||
$transaccion = $this->transaccionToArray($service, $cuenta, $transaccion);
|
||||
}
|
||||
}
|
||||
}
|
||||
$output = [
|
||||
'input' => compact('cuenta_id', 'month'),
|
||||
'cuenta' => $cuenta?->toArray(),
|
||||
'transacciones' => $transacciones
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function transaccionesAcumulation(Request $request, Response $response, Factory $factory, $cuenta_id, $date): Response {
|
||||
$cuenta = $factory->find(Cuenta::class)->one($cuenta_id);
|
||||
$f = Carbon::parse($date);
|
||||
$acum = 0;
|
||||
if ($cuenta !== null) {
|
||||
$acum = $cuenta->acumulacion($f);
|
||||
}
|
||||
$output = [
|
||||
'input' => compact('cuenta_id', 'date'),
|
||||
'cuenta' => $cuenta?->toArray(),
|
||||
'format' => $cuenta->moneda()->toArray(),
|
||||
'acumulation' => $acum
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function transaccionesAmount(Request $request, Response $response, Factory $factory, $cuenta_id): Response {
|
||||
$cuenta = $factory->find(Cuenta::class)->one($cuenta_id);
|
||||
$transacciones = 0;
|
||||
|
47
api/common/Controller/Queues.php
Normal file
47
api/common/Controller/Queues.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Controller;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use ProVM\Common\Factory\Model as Factory;
|
||||
use ProVM\Common\Define\Controller\Json;
|
||||
use Contabilidad\Queue;
|
||||
|
||||
class Queues {
|
||||
use Json;
|
||||
|
||||
public function __invoke(Request $request, Response $response, Factory $factory): Response {
|
||||
$queues = $factory->find(Queue::class)->many();
|
||||
$output = [
|
||||
'queues' => array_map(function($item) {return $item->toArray();}, $queues)
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function pending(Request $request, Response $response, Factory $factory): Response {
|
||||
$pending = $factory->find(Queue::class)->where([['processed', 0]])->many();
|
||||
$output = [
|
||||
'pending' => array_map(function($item) {return $item->toArray();}, $pending)
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function processed(Request $request, Response $response, Factory $factory): Response {
|
||||
$input = json_decode($request->getBody()->getContents());
|
||||
$output = [
|
||||
'input' => $input,
|
||||
'queues' => []
|
||||
];
|
||||
if (!is_array($input->processed)) {
|
||||
$input->processed = [$input->processed];
|
||||
}
|
||||
foreach ($input->processed as $id) {
|
||||
$queue = $factory->find(Queue::class)->one($id);
|
||||
$queue->setProcessed(true);
|
||||
$status = $queue->save();
|
||||
$output['queues'] []= [
|
||||
'queue' => $queue->toArray(),
|
||||
'processed' => $status
|
||||
];
|
||||
}
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Controller;
|
||||
|
||||
use Contabilidad\TipoCuenta;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use ProVM\Common\Define\Controller\Json;
|
||||
@ -23,19 +24,7 @@ class TiposCategorias {
|
||||
}, $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);
|
||||
});
|
||||
}
|
||||
$arr['totales'] = $item->getTotales($service);
|
||||
$item = $arr;
|
||||
});
|
||||
usort($tipos, function($a, $b) {
|
||||
@ -93,19 +82,7 @@ class TiposCategorias {
|
||||
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);
|
||||
});
|
||||
}
|
||||
$arr['totales'] = $item->getTotales($service);
|
||||
$item = $arr;
|
||||
});
|
||||
}
|
||||
@ -120,6 +97,19 @@ class TiposCategorias {
|
||||
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) {
|
||||
$totales = $item->getTotales($service);
|
||||
if (!is_array($sum)) {
|
||||
$sum = [];
|
||||
}
|
||||
foreach ($totales as $p => $total) {
|
||||
if (!isset($sum[$p])) {
|
||||
$sum[$p] = 0;
|
||||
}
|
||||
$sum[$p] += $total;
|
||||
}
|
||||
return $sum;
|
||||
});
|
||||
/*$balance = array_reduce($tipos, function($sum, $item) use ($service) {
|
||||
$maps = ['activo', 'pasivo', 'ganancia', 'perdida'];
|
||||
foreach ($maps as $m) {
|
||||
$p = $m . 's';
|
||||
@ -136,7 +126,7 @@ class TiposCategorias {
|
||||
});
|
||||
}
|
||||
return $sum;
|
||||
});
|
||||
});*/
|
||||
return $this->withJson($response, $balance);
|
||||
}
|
||||
}
|
||||
|
@ -5,24 +5,28 @@ 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\Queuer as Service;
|
||||
use Contabilidad\Transaccion;
|
||||
|
||||
class Transacciones {
|
||||
use Json;
|
||||
|
||||
protected function parseTransacciones(?array $transacciones): ?array {
|
||||
if ($transacciones !== null) {
|
||||
usort($transacciones, function($a, $b) {
|
||||
$d = $a['fecha'] - $b['fecha'];
|
||||
if ($d === 0) {
|
||||
return strcmp($a['cuenta']['nombre'], $b['cuenta']['nombre']);
|
||||
}
|
||||
return $d;
|
||||
});
|
||||
}
|
||||
return $transacciones;
|
||||
}
|
||||
public function __invoke(Request $request, Response $response, Factory $factory): Response {
|
||||
$transacciones = $factory->find(Transaccion::class)->array();
|
||||
if ($transacciones !== null) {
|
||||
usort($transacciones, function($a, $b) {
|
||||
$d = $a['fecha'] - $b['fecha'];
|
||||
if ($d === 0) {
|
||||
return strcmp($a['cuenta']['nombre'], $b['cuenta']['nombre']);
|
||||
}
|
||||
return $d;
|
||||
});
|
||||
}
|
||||
$output = [
|
||||
'transacciones' => $transacciones
|
||||
'transacciones' => $this->parseTransacciones($transacciones)
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
@ -52,17 +56,33 @@ class Transacciones {
|
||||
];
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
public function edit(Request $request, Response $response, Factory $factory, $transaccion_id): Response {
|
||||
public function edit(Request $request, Response $response, Factory $factory, Service $queuer, $transaccion_id): Response {
|
||||
$transaccion = $factory->find(Transaccion::class)->one($transaccion_id);
|
||||
$output = [
|
||||
'input' => $transaccion_id,
|
||||
'old' => $transaccion->toArray()
|
||||
];
|
||||
$old_cuentas = ['credito' => $transaccion->credito_id, 'debito_id' => $transaccion->debito_id];
|
||||
$input = json_decode($request->getBody());
|
||||
$transaccion->edit($input);
|
||||
$new_cuentas = ['credito' => $transaccion->credito_id, 'debito_id' => $transaccion->debito_id];
|
||||
$cuentas = [];
|
||||
foreach ($new_cuentas as $tipo => $id) {
|
||||
if ($old_cuentas[$tipo] != $id) {
|
||||
$cuentas []= $old_cuentas[$tipo];
|
||||
$cuentas []= $id;
|
||||
}
|
||||
}
|
||||
$this->updateConsolidar($queuer, $transaccion->fecha(), $cuentas);
|
||||
|
||||
$output['transaccion'] = $transaccion->toArray();
|
||||
return $this->withJson($response, $output);
|
||||
}
|
||||
protected function updateConsolidar(Service $queuer, \DateTimeInterface $mes, $cuentas) {
|
||||
foreach ($cuentas as $cuenta_id) {
|
||||
$queuer->queue('update_consolidar', ['mes' => $mes->format('Y-m-1'), 'cuenta' => $cuenta_id]);
|
||||
}
|
||||
}
|
||||
public function delete(Request $request, Response $response, Factory $factory, $transaccion_id): Response {
|
||||
$transaccion = $factory->find(Transaccion::class)->one($transaccion_id);
|
||||
$output = [
|
||||
|
20
api/common/Middleware/Consolidar.php
Normal file
20
api/common/Middleware/Consolidar.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?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 Contabilidad\Common\Service\Consolidar as ConsolidarService;
|
||||
|
||||
class Consolidar {
|
||||
protected $service;
|
||||
public function __construct(ConsolidarService $service) {
|
||||
$this->service = $service;
|
||||
}
|
||||
public function __invoke(Request $request, Handler $handler): Response {
|
||||
if (!$this->service->isConsolidado()) {
|
||||
$this->service->queue();
|
||||
}
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
174
api/common/Service/Consolidar.php
Normal file
174
api/common/Service/Consolidar.php
Normal file
@ -0,0 +1,174 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Service;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use \Model;
|
||||
use ProVM\Common\Factory\Model as ModelFactory;
|
||||
use Contabilidad\Consolidado;
|
||||
use Contabilidad\Cuenta;
|
||||
use Contabilidad\Transaccion;
|
||||
|
||||
class Consolidar {
|
||||
public function __construct(ModelFactory $factory, Queuer $queuer) {
|
||||
$this->setFactory($factory);
|
||||
$this->setQueuer($queuer);
|
||||
}
|
||||
protected ModelFactory $factory;
|
||||
public function setFactory(ModelFactory $factory): Consolidar {
|
||||
$this->factory = $factory;
|
||||
return $this;
|
||||
}
|
||||
protected Queuer $queuer;
|
||||
public function setQueuer(Queuer $queuer): Consolidar {
|
||||
$this->queuer = $queuer;
|
||||
return $this;
|
||||
}
|
||||
protected $cuentas;
|
||||
public function getCuentas() {
|
||||
if ($this->cuentas === null) {
|
||||
$this->cuentas = $this->factory->find(Cuenta::class)->many();
|
||||
}
|
||||
return $this->cuentas;
|
||||
}
|
||||
|
||||
public function isConsolidado(): bool {
|
||||
$cuentas = $this->getCuentas();
|
||||
if ($cuentas === null) {
|
||||
return true;
|
||||
}
|
||||
foreach ($cuentas as $cuenta) {
|
||||
$transacciones = $cuenta->hasTransacciones();
|
||||
if (!$transacciones) {
|
||||
continue;
|
||||
}
|
||||
$pendientes = $cuenta->hasConsolidadosPending();
|
||||
if ($pendientes) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public function queue() {
|
||||
$this->queuer->queue('consolidar');
|
||||
}
|
||||
public function consolidar() {
|
||||
ini_set('max_execution_time', 60*5);
|
||||
|
||||
foreach ($this->getCuentas() as $cuenta) {
|
||||
if (!$cuenta->hasTransacciones()) {
|
||||
continue;
|
||||
}
|
||||
$first = $this->getFirst($cuenta);
|
||||
$last = $this->getLast($cuenta);
|
||||
for ($current = $first->copy()->startOfMonth(); $current < $last->copy()->addMonthWithoutOverflow()->endOfMonth(); $current = $current->copy()->addMonthWithoutOverflow()) {
|
||||
$this->consolidarCuenta($cuenta, $current);
|
||||
}
|
||||
}
|
||||
}
|
||||
public function consolidarCuenta(Cuenta $cuenta, Carbon $mes) {
|
||||
if (!$cuenta->hasTransacciones($mes)) {
|
||||
return;
|
||||
}
|
||||
$transacciones = $this->getTransacciones($cuenta, $mes);
|
||||
if (count($transacciones) == 0) {
|
||||
return;
|
||||
}
|
||||
array_walk($transacciones, function(&$item) use ($cuenta) {
|
||||
$item->valor = $item->transformar($cuenta->moneda());
|
||||
});
|
||||
$saldo = array_reduce($transacciones, function($sum, $item) {
|
||||
return $sum + $item->valor;
|
||||
});
|
||||
if ($cuenta->tipo()->cargo()) {
|
||||
$saldo += -1;
|
||||
}
|
||||
$consolidado = $this->factory->find(Consolidado::class)->where([['cuenta_id', $cuenta->id], ['fecha', $mes->format('Y-m-1')]])->one();
|
||||
if ($consolidado === null) {
|
||||
$data = [
|
||||
'cuenta_id' => $cuenta->id,
|
||||
'fecha' => $mes->format('Y-m-1'),
|
||||
'periodo' => 'P1M',
|
||||
'saldo' => $saldo
|
||||
];
|
||||
$consolidado = $this->factory->create(Consolidado::class, $data);
|
||||
}
|
||||
$consolidado->saldo = $saldo;
|
||||
$consolidado->save();
|
||||
}
|
||||
public function getFirst(Cuenta $cuenta): ?Carbon {
|
||||
$first = [
|
||||
Model::factory(Transaccion::class)
|
||||
->select('fecha')
|
||||
->whereEqual('debito_id', $cuenta->id)
|
||||
->orderByAsc('fecha')
|
||||
->findOne(),
|
||||
Model::factory(Transaccion::class)
|
||||
->select('fecha')
|
||||
->whereEqual('credito_id', $cuenta->id)
|
||||
->orderByAsc('fecha')
|
||||
->findOne()
|
||||
];
|
||||
if (!$first[0]) {
|
||||
if (!$first[1]) {
|
||||
return null;
|
||||
}
|
||||
return $first[1]->fecha();
|
||||
}
|
||||
if (!$first[1]) {
|
||||
return $first[0]->fecha();
|
||||
}
|
||||
if ($first[0]->fecha() < $first[1]->fecha()) {
|
||||
return $first[0]->fecha();
|
||||
}
|
||||
return $first[1]->fecha();
|
||||
}
|
||||
public function getLast(Cuenta $cuenta): ?Carbon {
|
||||
$fechas = [
|
||||
Model::factory(Transaccion::class)
|
||||
->select('fecha')
|
||||
->whereEqual('debito_id', $cuenta->id)
|
||||
->orderByDesc('fecha')
|
||||
->findOne(),
|
||||
Model::factory(Transaccion::class)
|
||||
->select('fecha')
|
||||
->whereEqual('credito_id', $cuenta->id)
|
||||
->orderByDesc('fecha')
|
||||
->findOne()
|
||||
];
|
||||
if (!$fechas[0]) {
|
||||
if (!$fechas[1]) {
|
||||
return null;
|
||||
}
|
||||
return $fechas[1]->fecha();
|
||||
}
|
||||
if (!$fechas[1]) {
|
||||
return $fechas[0]->fecha();
|
||||
}
|
||||
if ($fechas[0]->fecha() > $fechas[1]->fecha()) {
|
||||
return $fechas[0]->fecha();
|
||||
}
|
||||
return $fechas[1]->fecha();
|
||||
}
|
||||
public function getTransacciones(Cuenta $cuenta, Carbon $fecha) {
|
||||
$start = $fecha->copy()->startOfMonth();
|
||||
$end = $fecha->copy()->endOfMonth();
|
||||
$debitos = Model::factory(Transaccion::class)
|
||||
->whereEqual('debito_id', $cuenta->id)
|
||||
->whereRaw("fecha BETWEEN '{$start->format('Y-m-d')}' AND '{$end->format('Y-m-d')}'")
|
||||
->findMany();
|
||||
if ($debitos) {
|
||||
array_walk($debitos, function(&$item) {
|
||||
$item->valor *= -1;
|
||||
});
|
||||
}
|
||||
$creditos = Model::factory(Transaccion::class)
|
||||
->whereEqual('credito_id', $cuenta->id)
|
||||
->whereRaw("fecha BETWEEN '{$start->format('Y-m-d')}' AND '{$end->format('Y-m-d')}'")
|
||||
->findMany();
|
||||
$transacciones = array_merge($debitos, $creditos);
|
||||
foreach ($transacciones as &$transaccion) {
|
||||
$transaccion->setFactory($this->factory);
|
||||
}
|
||||
return $transacciones;
|
||||
}
|
||||
}
|
47
api/common/Service/Queuer.php
Normal file
47
api/common/Service/Queuer.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Service;
|
||||
|
||||
use ProVM\Common\Factory\Model as Factory;
|
||||
use Contabilidad\Queue;
|
||||
use Contabilidad\QueueArgument;
|
||||
|
||||
class Queuer {
|
||||
protected Factory $factory;
|
||||
public function __construct(Factory $factory) {
|
||||
$this->setFactory($factory);
|
||||
}
|
||||
public function setFactory(Factory $factory): Queuer {
|
||||
$this->factory = $factory;
|
||||
return $this;
|
||||
}
|
||||
public function queue(string $command, array $arguments = []) {
|
||||
if ($this->isProcessed($command, $arguments)) {
|
||||
return;
|
||||
}
|
||||
$queue = $this->factory->create(Queue::class, ['command' => $command, 'created' => (new \DateTime('now'))->format('Y-m-d H:i:s')]);
|
||||
$queue->save();
|
||||
if (count($arguments) > 0) {
|
||||
foreach ($arguments as $argument => $value) {
|
||||
$arg = $this->factory->create(QueueArgument::class, ['queue_id' => $queue->id, 'argument' => $argument, 'value' => $value]);
|
||||
$arg->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
public function isProcessed(string $command, array $arguments = []): bool {
|
||||
$queues = $this->find($command, $arguments);
|
||||
if ($queues == null or count($queues) === 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public function find(string $command, array $arguments = []): ?array {
|
||||
$queues = $this->factory->find(Queue::class)->where([['command', $command], ['processed', 0]])->many();
|
||||
if ($queues === null) {
|
||||
return null;
|
||||
}
|
||||
if (count($arguments) > 0) {
|
||||
$queues = array_filter($queues, function($item) use ($arguments) {return count($arguments) === count($item->matchArguments($arguments));});
|
||||
}
|
||||
return $queues;
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@ final class Categoria extends AbstractMigration
|
||||
$this->table('categorias')
|
||||
->addColumn('nombre', 'string')
|
||||
->addColumn('tipo_id', 'integer')
|
||||
->addForeignKey('tipo_id', 'tipos_categoria')
|
||||
->addForeignKey('tipo_id', 'tipos_categoria', ['delete' => 'cascade', 'update' => 'cascade'])
|
||||
->create();
|
||||
}
|
||||
}
|
||||
|
@ -21,9 +21,9 @@ final class Cuenta extends AbstractMigration
|
||||
$this->table('cuentas')
|
||||
->addColumn('nombre', 'string')
|
||||
->addColumn('categoria_id', 'integer')
|
||||
->addForeignKey('categoria_id', 'categorias')
|
||||
->addForeignKey('categoria_id', 'categorias', ['delete' => 'cascade', 'update' => 'cascade'])
|
||||
->addColumn('tipo_id', 'integer')
|
||||
->addForeignKey('tipo_id', 'tipos_cuenta')
|
||||
->addForeignKey('tipo_id', 'tipos_cuenta', ['delete' => 'cascade', 'update' => 'cascade'])
|
||||
->create();
|
||||
}
|
||||
}
|
||||
|
@ -20,10 +20,10 @@ final class EstadoConeccion extends AbstractMigration
|
||||
{
|
||||
$this->table('estados_coneccion')
|
||||
->addColumn('coneccion_id', 'integer')
|
||||
->addForeignKey('coneccion_id', 'conecciones')
|
||||
->addForeignKey('coneccion_id', 'conecciones', ['delete' => 'cascade', 'update' => 'cascade'])
|
||||
->addColumn('fecha', 'date')
|
||||
->addColumn('tipo_id', 'integer')
|
||||
->addForeignKey('tipo_id', 'tipos_estado_coneccion')
|
||||
->addForeignKey('tipo_id', 'tipos_estado_coneccion', ['delete' => 'cascade', 'update' => 'cascade'])
|
||||
->create();
|
||||
}
|
||||
}
|
||||
|
@ -20,9 +20,9 @@ final class Transaccion extends AbstractMigration
|
||||
{
|
||||
$this->table('transacciones')
|
||||
->addColumn('debito_id', 'integer')
|
||||
->addForeignKey('debito_id', 'cuentas')
|
||||
->addForeignKey('debito_id', 'cuentas', ['delete' => 'cascade', 'update' => 'cascade'])
|
||||
->addColumn('credito_id', 'integer')
|
||||
->addForeignKey('credito_id', 'cuentas')
|
||||
->addForeignKey('credito_id', 'cuentas', ['delete' => 'cascade', 'update' => 'cascade'])
|
||||
->addColumn('fecha', 'datetime')
|
||||
->addColumn('glosa', 'string')
|
||||
->addColumn('detalle', 'text')
|
||||
|
@ -20,7 +20,7 @@ final class CuentaMoneda extends AbstractMigration
|
||||
{
|
||||
$this->table('cuentas')
|
||||
->addColumn('moneda_id', 'integer')
|
||||
->addForeignKey('moneda_id', 'monedas')
|
||||
->addForeignKey('moneda_id', 'monedas', ['delete' => 'cascade', 'update' => 'cascade'])
|
||||
->update();
|
||||
}
|
||||
}
|
||||
|
@ -21,9 +21,9 @@ final class TipoCambio extends AbstractMigration
|
||||
$this->table('tipos_cambio')
|
||||
->addColumn('fecha', 'datetime')
|
||||
->addColumn('desde_id', 'integer')
|
||||
->addForeignKey('desde_id', 'monedas')
|
||||
->addForeignKey('desde_id', 'monedas', ['delete' => 'cascade', 'update' => 'cascade'])
|
||||
->addColumn('hasta_id', 'integer')
|
||||
->addForeignKey('hasta_id', 'monedas')
|
||||
->addForeignKey('hasta_id', 'monedas', ['delete' => 'cascade', 'update' => 'cascade'])
|
||||
->addColumn('valor', 'double')
|
||||
->create();
|
||||
}
|
||||
|
27
api/db/migrations/20220325185534_queue.php
Normal file
27
api/db/migrations/20220325185534_queue.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class Queue 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('queue')
|
||||
->addColumn('command', 'string')
|
||||
->addColumn('created', 'datetime')
|
||||
->addColumn('processed', 'boolean', ['default' => 0])
|
||||
->create();
|
||||
}
|
||||
}
|
28
api/db/migrations/20220325185539_queue_arguments.php
Normal file
28
api/db/migrations/20220325185539_queue_arguments.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class QueueArguments 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('queue_arguments')
|
||||
->addColumn('queue_id', 'integer')
|
||||
->addForeignKey('queue_id', 'queue', ['delete' => 'cascade', 'update' => 'cascade'])
|
||||
->addColumn('argument', 'string', ['length' => 100])
|
||||
->addColumn('value', 'string')
|
||||
->create();
|
||||
}
|
||||
}
|
29
api/db/migrations/20220325191129_consolidados.php
Normal file
29
api/db/migrations/20220325191129_consolidados.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class Consolidados 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('consolidados')
|
||||
->addColumn('cuenta_id', 'integer')
|
||||
->addForeignKey('cuenta_id', 'cuentas', ['delete' => 'cascade', 'update' => 'cascade'])
|
||||
->addColumn('fecha', 'date')
|
||||
->addColumn('periodo', 'string', ['length' => 50])
|
||||
->addColumn('saldo', 'double')
|
||||
->create();
|
||||
}
|
||||
}
|
@ -1,7 +1,13 @@
|
||||
<?php
|
||||
require_once implode(DIRECTORY_SEPARATOR, [
|
||||
dirname(__DIR__),
|
||||
'setup',
|
||||
'app.php'
|
||||
]);
|
||||
$app->run();
|
||||
try {
|
||||
ini_set('error_reporting', E_ALL & ~E_NOTICE & ~E_DEPRECATED);
|
||||
$app = require_once implode(DIRECTORY_SEPARATOR, [
|
||||
dirname(__DIR__),
|
||||
'setup',
|
||||
'app.php'
|
||||
]);
|
||||
$app->run();
|
||||
} catch (Error | Exception $e) {
|
||||
error_log($e);
|
||||
throw $e;
|
||||
}
|
||||
|
7
api/resources/routes/consolidar.php
Normal file
7
api/resources/routes/consolidar.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Consolidados;
|
||||
|
||||
$app->group('/consolidar', function($app) {
|
||||
$app->get('/update/{mes}/{cuenta_id}', [Consolidados::class, 'update']);
|
||||
$app->get('[/]', [Consolidados::class, 'cli']);
|
||||
});
|
@ -9,6 +9,8 @@ $app->group('/cuenta/{cuenta_id}', function($app) {
|
||||
$app->get('/entradas', [Cuentas::class, 'entradas']);
|
||||
$app->group('/transacciones', function($app) {
|
||||
$app->get('/amount', [Cuentas::class, 'transaccionesAmount']);
|
||||
$app->get('/month/{month}', [Cuentas::class, 'transaccionesMonth']);
|
||||
$app->get('/acum/{date}', [Cuentas::class, 'transaccionesAcumulation']);
|
||||
$app->get('[/{limit:[0-9]+}[/{start:[0-9]+}]]', [Cuentas::class, 'transacciones']);
|
||||
});
|
||||
$app->get('/categoria', [Cuentas::class, 'categoria']);
|
||||
|
8
api/resources/routes/queues.php
Normal file
8
api/resources/routes/queues.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Queues;
|
||||
|
||||
$app->group('/queues', function($app) {
|
||||
$app->get('/pending', [Queues::class, 'pending']);
|
||||
$app->post('/processed', [Queues::class, 'processed']);
|
||||
$app->get('[/]', Queues::class);
|
||||
});
|
@ -2,11 +2,11 @@
|
||||
use Contabilidad\Common\Controller\Transacciones;
|
||||
|
||||
$app->group('/transacciones', function($app) {
|
||||
$app->post('/add[/]', [Transacciones::class, 'add']);
|
||||
$app->get('[/]', Transacciones::class);
|
||||
$app->post('/add[/]', [Transacciones::class, 'add']);
|
||||
$app->get('[/]', Transacciones::class);
|
||||
});
|
||||
$app->group('/transaccion/{transaccion_id}', function($app) {
|
||||
$app->put('/edit', [Transacciones::class, 'edit']);
|
||||
$app->delete('/delete', [Transacciones::class, 'delete']);
|
||||
$app->get('[/]', [Transacciones::class, 'show']);
|
||||
$app->put('/edit', [Transacciones::class, 'edit']);
|
||||
$app->delete('/delete', [Transacciones::class, 'delete']);
|
||||
$app->get('[/]', [Transacciones::class, 'show']);
|
||||
});
|
||||
|
@ -44,3 +44,5 @@ if (file_exists($folder)) {
|
||||
|
||||
include_once 'databases.php';
|
||||
include_once 'router.php';
|
||||
|
||||
return $app;
|
||||
|
4
api/setup/middlewares/03_consolidar.php
Normal file
4
api/setup/middlewares/03_consolidar.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Middleware\Consolidar;
|
||||
|
||||
$app->add(new Consolidar($app->getContainer()->get(\Contabilidad\Common\Service\Consolidar::class)));
|
11
api/setup/setups/03_consolidar.php
Normal file
11
api/setup/setups/03_consolidar.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
use Psr\Container\ContainerInterface as Container;
|
||||
|
||||
return [
|
||||
\Contabilidad\Common\Service\Queuer::class => function(Container $container) {
|
||||
return new \Contabilidad\Common\Service\Queuer($container->get(\ProVM\Common\Factory\Model::class));
|
||||
},
|
||||
\Contabilidad\Common\Service\Consolidar::class => function(Container $container) {
|
||||
return new \Contabilidad\Common\Service\Consolidar($container->get(\ProVM\Common\Factory\Model::class), $container->get(\Contabilidad\Common\Service\Queuer::class));
|
||||
}
|
||||
];
|
@ -46,33 +46,43 @@ class Categoria extends Model {
|
||||
])
|
||||
->many();
|
||||
}
|
||||
protected $activos;
|
||||
public function activos() {
|
||||
if ($this->activos === null) {
|
||||
$this->activos = $this->getCuentasOf('Activo');
|
||||
protected $cuentas_of;
|
||||
public function getCuentas() {
|
||||
if ($this->cuentas_of === null) {
|
||||
$tipos = $this->factory->find(TipoCuenta::class)->many();
|
||||
$cos = [];
|
||||
foreach ($tipos as $tipo) {
|
||||
$p = strtolower($tipo->descripcion) . 's';
|
||||
$cos[$p] = [];
|
||||
$cuentas = $this->getCuentasOf($tipos->descripcion);
|
||||
if ($cuentas === null) {
|
||||
continue;
|
||||
}
|
||||
$cos[$p] = $cuentas;
|
||||
}
|
||||
$this->cuentas_of = $cos;
|
||||
}
|
||||
return $this->activos();
|
||||
return $this->cuentas_of;
|
||||
}
|
||||
protected $pasivos;
|
||||
public function pasivos() {
|
||||
if ($this->pasivos === null) {
|
||||
$this->activos = $this->getCuentasOf('Pasivo');
|
||||
protected $totales;
|
||||
public function getTotales(Service $service) {
|
||||
if ($this->totales === null) {
|
||||
$tipos = $this->factory->find(TipoCuenta::class)->many();
|
||||
$totals = [];
|
||||
foreach ($tipos as $tipo) {
|
||||
$p = strtolower($tipo->descripcion) . 's';
|
||||
$totals[$p] = 0;
|
||||
$cuentas = $this->getCuentasOf($tipo->descripcion);
|
||||
if ($cuentas === null) {
|
||||
continue;
|
||||
}
|
||||
$totals[$p] = array_reduce($cuentas, function($sum, $item) use ($service) {
|
||||
return $sum + $item->saldo($service, true);
|
||||
});
|
||||
}
|
||||
$this->totales = $totals;
|
||||
}
|
||||
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;
|
||||
return $this->totales;
|
||||
}
|
||||
|
||||
protected $saldo;
|
||||
|
48
api/src/Consolidado.php
Normal file
48
api/src/Consolidado.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
namespace Contabilidad;
|
||||
|
||||
use DateTimeInterface;
|
||||
use DateInterval;
|
||||
use Carbon\Carbon;
|
||||
use Carbon\CarbonInterval;
|
||||
use ProVM\Common\Alias\Model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property Cuenta $cuenta_id
|
||||
* @property DateTimeInterface $fecha
|
||||
* @property DateInterval $periodo
|
||||
* @property float $saldo
|
||||
*/
|
||||
class Consolidado extends Model {
|
||||
public static $_table = 'consolidados';
|
||||
|
||||
protected $cuenta;
|
||||
public function cuenta() {
|
||||
if ($this->cuenta === null) {
|
||||
$this->cuenta = $this->childOf(Cuenta::class, [Model::SELF_KEY => 'cuenta_id']);
|
||||
}
|
||||
return $this->cuenta;
|
||||
}
|
||||
public function fecha(DateTimeInterface $fecha = null) {
|
||||
if ($fecha === null) {
|
||||
return Carbon::parse($this->fecha);
|
||||
}
|
||||
if ($this->periodo()->days > 31) {
|
||||
$this->fecha = $fecha->format('Y-1-1');
|
||||
} else {
|
||||
$this->fecha = $fecha->format('Y-m-1');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function periodo(DateInterval $periodo = null) {
|
||||
if ($periodo === null) {
|
||||
return new CarbonInterval($this->periodo);
|
||||
}
|
||||
$this->periodo = CarbonInterval::getDateIntervalSpec($periodo);
|
||||
return $this;
|
||||
}
|
||||
public function saldo() {
|
||||
return $this->saldo;
|
||||
}
|
||||
}
|
@ -52,9 +52,62 @@ class Cuenta extends Model {
|
||||
}
|
||||
return $this->abonos;
|
||||
}
|
||||
protected $consolidados;
|
||||
public function consolidados() {
|
||||
if ($this->consolidados === null) {
|
||||
$this->consolidados = $this->parentOf(Consolidado::class, [Model::CHILD_KEY => 'cuenta_id']);
|
||||
}
|
||||
return $this->consolidados;
|
||||
}
|
||||
public function hasConsolidados(\DateTimeInterface $mes = null): bool {
|
||||
$t = Carbon::now();
|
||||
$q = Model::factory(Consolidado::class)
|
||||
->whereEqual('cuenta_id', $this->id);
|
||||
if ($mes !== null) {
|
||||
//$q = $q->whereEqual('fecha', $mes->format('Y-m-1'));
|
||||
$q = $q->whereRaw("fecha BETWEEN '{$mes->format('Y-m-1')}' AND '{$mes->format('Y-m-t')}'");
|
||||
}
|
||||
$q = $q->count('id');
|
||||
return (bool) $q;
|
||||
}
|
||||
public function hasConsolidadosPending(\DateTimeInterface $mes = null): bool {
|
||||
$t = Carbon::now();
|
||||
$q = Model::factory(Consolidado::class)
|
||||
->whereEqual('cuenta_id', $this->id)
|
||||
->whereGte('fecha', $t->copy()->subMonthNoOverflow()->startOfMonth()->format('Y-m-d'));
|
||||
if ($mes !== null) {
|
||||
$q = $q->whereRaw("fecha BETWEEN '{$mes->format('Y-m-1')}' AND '{$mes->format('Y-m-t')}'");
|
||||
}
|
||||
return !(bool) $q
|
||||
->orderByDesc('fecha')
|
||||
->count('id');
|
||||
}
|
||||
public function hasTransacciones(\DateTimeInterface $mes = null): bool {
|
||||
$q = Model::factory(Transaccion::class)
|
||||
->select('transacciones.*')
|
||||
->join('cuentas', 'cuentas.id = transacciones.debito_id OR cuentas.id = transacciones.credito_id')
|
||||
->whereEqual('cuentas.id', $this->id);
|
||||
if ($mes !== null) {
|
||||
$q = $q->whereRaw("fecha BETWEEN '{$mes->format('Y-m-1')}' AND '{$mes->format('Y-m-t')}'");
|
||||
}
|
||||
return (bool) $q->count('transacciones.id');
|
||||
}
|
||||
protected $transacciones;
|
||||
protected function parseTransaccion(Transaccion $transaccion) {
|
||||
$transaccion->setFactory($this->factory);
|
||||
if ($this->tipo()->cargo()) {
|
||||
if ($transaccion->credito_id == $this->id) {
|
||||
$transaccion->valor = -$transaccion->valor;
|
||||
}
|
||||
} else {
|
||||
if ($transaccion->debito_id == $this->id) {
|
||||
$transaccion->valor = -$transaccion->valor;
|
||||
}
|
||||
}
|
||||
$transaccion->valor = $transaccion->transformar($this->moneda());
|
||||
return $transaccion;
|
||||
}
|
||||
public function transacciones($limit = null, $start = 0) {
|
||||
if ($this->transacciones === null) {
|
||||
$transacciones = Model::factory(Transaccion::class)
|
||||
->select('transacciones.*')
|
||||
->join('cuentas', 'cuentas.id = transacciones.debito_id OR cuentas.id = transacciones.credito_id')
|
||||
@ -64,15 +117,43 @@ class Cuenta extends Model {
|
||||
$transacciones = $transacciones->limit($limit)
|
||||
->offset($start);
|
||||
}
|
||||
$this->transacciones = $transacciones->findMany();
|
||||
foreach ($this->transacciones as &$transaccion) {
|
||||
$transaccion->setFactory($this->factory);
|
||||
if ($transaccion->desde_id === $this->id) {
|
||||
$transaccion->valor = - $transaccion->valor;
|
||||
}
|
||||
$transacciones = $transacciones->findMany();
|
||||
foreach ($transacciones as &$transaccion) {
|
||||
$transaccion = $this->parseTransaccion($transaccion);
|
||||
}
|
||||
}
|
||||
return $this->transacciones;
|
||||
return $transacciones;
|
||||
}
|
||||
public function transaccionesMonth(Carbon $month) {
|
||||
$start = $month->copy()->startOfMonth();
|
||||
$end = $month->copy()->endOfMonth();
|
||||
|
||||
$transacciones = Model::factory(Transaccion::class)
|
||||
->select('transacciones.*')
|
||||
->join('cuentas', 'cuentas.id = transacciones.debito_id OR cuentas.id = transacciones.credito_id')
|
||||
->whereEqual('cuentas.id', $this->id)
|
||||
->whereRaw("transacciones.fecha BETWEEN '{$start->format('Y-m-d')}' AND '{$end->format('Y-m-d')}'")
|
||||
->orderByAsc('transacciones.fecha');
|
||||
$transacciones = $transacciones->findMany();
|
||||
|
||||
foreach ($transacciones as &$transaccion) {
|
||||
$transaccion = $this->parseTransaccion($transaccion);
|
||||
}
|
||||
|
||||
return $transacciones;
|
||||
}
|
||||
public function acumulacion(Carbon $date) {
|
||||
$consolidados = $this->consolidados();
|
||||
if ($consolidados === null) {
|
||||
return 0;
|
||||
}
|
||||
$saldo = 0;
|
||||
foreach ($consolidados as $consolidado) {
|
||||
if ($consolidado->fecha() >= $date) {
|
||||
continue;
|
||||
}
|
||||
$saldo += $consolidado->saldo();
|
||||
}
|
||||
return $saldo;
|
||||
}
|
||||
protected $saldo;
|
||||
public function saldo(Service $service = null, $in_clp = false) {
|
||||
|
@ -16,25 +16,28 @@ class Moneda extends Model {
|
||||
protected static $fields = ['denominacion', 'codigo'];
|
||||
|
||||
public function format($valor) {
|
||||
return implode('', [
|
||||
return trim(implode('', [
|
||||
$this->prefijo,
|
||||
number_format($valor, $this->decimales, ',', '.'),
|
||||
$this->sufijo
|
||||
]);
|
||||
]));
|
||||
}
|
||||
public function cambio(\DateTime $fecha) {
|
||||
public function cambio(\DateTime $fecha, Moneda $moneda = null) {
|
||||
if ($moneda === null) {
|
||||
$moneda = $this->factory->find(Moneda::class)->one(1);
|
||||
}
|
||||
$cambio = $this->factory->find(TipoCambio::class)
|
||||
->where([['desde_id', $this->id], ['hasta_id', 1], ['fecha', $fecha->format('Y-m-d H:i:s')]])
|
||||
->where([['desde_id', $this->id], ['hasta_id', $moneda->id], ['fecha', $fecha->format('Y-m-d H:i:s')]])
|
||||
->one();
|
||||
if ($cambio === null) {
|
||||
$cambio = $this->factory->find(TipoCambio::class)
|
||||
->where([['hasta_id', $this->id], ['desde_id', 1], ['fecha', $fecha->format('Y-m-d H:i:s')]])
|
||||
->where([['hasta_id', $this->id], ['desde_id', $moneda->id], ['fecha', $fecha->format('Y-m-d H:i:s')]])
|
||||
->one();
|
||||
}
|
||||
return $cambio;
|
||||
}
|
||||
public function cambiar(\DateTime $fecha, float $valor) {
|
||||
$cambio = $this->cambio($fecha);
|
||||
public function cambiar(\DateTime $fecha, float $valor, Moneda $moneda = null) {
|
||||
$cambio = $this->cambio($fecha, $moneda);
|
||||
if (!$cambio) {
|
||||
return $valor;
|
||||
}
|
||||
@ -43,4 +46,14 @@ class Moneda extends Model {
|
||||
}
|
||||
return $cambio->transform($valor);
|
||||
}
|
||||
|
||||
public function toArray(): array {
|
||||
$arr = parent::toArray();
|
||||
$arr['format'] = [
|
||||
'prefijo' => $this->prefijo,
|
||||
'sufijo' => $this->sufijo,
|
||||
'decimales' => $this->decimales
|
||||
];
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
|
98
api/src/Queue.php
Normal file
98
api/src/Queue.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
namespace Contabilidad;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Carbon\Carbon;
|
||||
use ProVM\Common\Alias\Model;
|
||||
use ProVM\Common\Factory\Model as Factory;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $command
|
||||
* @property DateTimeInterface $created
|
||||
* @property bool $processed
|
||||
*/
|
||||
class Queue extends Model {
|
||||
public static $_table = 'queue';
|
||||
protected static $fields = ['command', 'created', 'processed'];
|
||||
|
||||
public function created(DateTimeInterface $fecha = null) {
|
||||
if ($fecha === null) {
|
||||
return Carbon::parse($this->created);
|
||||
}
|
||||
$this->created = $fecha->format('Y-m-d H:i:s');
|
||||
return $this;
|
||||
}
|
||||
public function hasArguments(): bool {
|
||||
return Model::factory(QueueArgument::class)
|
||||
->whereEqual('queue_id', $this->id)
|
||||
->groupBy('queue_id')
|
||||
->count('id') > 0;
|
||||
}
|
||||
protected $arguments;
|
||||
public function arguments() {
|
||||
if ($this->arguments === null) {
|
||||
$this->arguments = $this->parentOf(QueueArgument::class, [Model::CHILD_KEY => 'queue_id']);
|
||||
}
|
||||
return $this->arguments;
|
||||
}
|
||||
public function matchArguments(array $arguments): array {
|
||||
$args = $this->arguments();
|
||||
if ($args === null) {
|
||||
return [];
|
||||
}
|
||||
$matched = [];
|
||||
foreach ($arguments as $argument => $value) {
|
||||
foreach ($args as $arg) {
|
||||
if ($arg->argument == $argument and $arg->value == $value) {
|
||||
$matched []= $arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $matched;
|
||||
}
|
||||
public function isProcessed(): bool {
|
||||
return $this->processed > 0;
|
||||
}
|
||||
public function setProcessed(bool $processed): Queue {
|
||||
$this->processed = $processed ? 1 : 0;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public static function find(Factory $factory, $data) {
|
||||
$where = [
|
||||
'command' => $data['command'],
|
||||
'processed' => $data['processed'] ?? 0
|
||||
];
|
||||
array_walk($where, function(&$item, $key) {
|
||||
$item = [$key, $item];
|
||||
});
|
||||
$where = array_values($where);
|
||||
return $factory->find(Queue::class)->where($where)->one();
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
$arr = parent::toArray();
|
||||
$cmd = [(string) $this];
|
||||
$arr['arguments'] = [];
|
||||
if ($this->hasArguments()) {
|
||||
$arr['arguments'] = array_map(function($item) use (&$cmd) {
|
||||
$cmd []= (string) $item;
|
||||
return $item->toArray();
|
||||
}, $this->arguments());
|
||||
}
|
||||
$arr['cmd'] = implode(' ', $cmd);
|
||||
return $arr;
|
||||
}
|
||||
|
||||
public function __toString(): string {
|
||||
$str = "{$this->command}";
|
||||
$arguments = $this->arguments();
|
||||
if ($arguments !== null and count($arguments) > 0) {
|
||||
$arguments = implode(' ', array_map(function($item) {return (string) $item;}, $arguments));
|
||||
$str .= " {$arguments}";
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
}
|
26
api/src/QueueArgument.php
Normal file
26
api/src/QueueArgument.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
namespace Contabilidad;
|
||||
|
||||
use ProVM\Common\Alias\Model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property Queue $queue_id
|
||||
* @property string $argument
|
||||
* @property string $value
|
||||
*/
|
||||
class QueueArgument extends Model {
|
||||
public static $_table = 'queue_arguments';
|
||||
|
||||
protected $queue;
|
||||
public function queue() {
|
||||
if ($this->queue === null) {
|
||||
$this->queue = $this->childOf(Queue::class, [Model::SELF_KEY => 'queue_id']);
|
||||
}
|
||||
return $this->queue;
|
||||
}
|
||||
|
||||
public function __toString(): string {
|
||||
return "--{$this->argument} '{$this->value}'";
|
||||
}
|
||||
}
|
@ -33,6 +33,26 @@ class TipoCategoria extends Model {
|
||||
['categorias.tipo_id', $this->id]
|
||||
])->many();
|
||||
}
|
||||
protected $totales;
|
||||
public function getTotales(Service $service) {
|
||||
if ($this->totales === null) {
|
||||
$tipos = $this->factory->find(TipoCuenta::class)->many();
|
||||
$totals = [];
|
||||
foreach ($tipos as $tipo) {
|
||||
$p = strtolower($tipo->descripcion) . 's';
|
||||
$totals[$p] = 0;
|
||||
$cuentas = $this->getCuentasOf($tipo->descripcion);
|
||||
if ($cuentas === null) {
|
||||
continue;
|
||||
}
|
||||
$totals[$p] = array_reduce($cuentas, function($sum, $item) use ($service) {
|
||||
return $sum + $item->saldo($service, true);
|
||||
});
|
||||
}
|
||||
$this->totales = $totals;
|
||||
}
|
||||
return $this->totales;
|
||||
}
|
||||
|
||||
protected $saldo;
|
||||
public function saldo(Service $service = null) {
|
||||
|
@ -9,6 +9,19 @@ use ProVM\Common\Alias\Model;
|
||||
* @property string $color
|
||||
*/
|
||||
class TipoCuenta extends Model {
|
||||
public static $_table = 'tipos_cuenta';
|
||||
protected static $fields = ['descripcion', 'color'];
|
||||
public static $_table = 'tipos_cuenta';
|
||||
protected static $fields = ['descripcion', 'color'];
|
||||
|
||||
public function cargo()
|
||||
{
|
||||
$tipos = [
|
||||
'activo',
|
||||
'perdida',
|
||||
'banco'
|
||||
];
|
||||
if (in_array(strtolower($this->descripcion), $tipos)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -13,10 +13,11 @@ use ProVM\Common\Alias\Model;
|
||||
* @property string $glosa
|
||||
* @property string $detalle
|
||||
* @property double $valor
|
||||
* @property Moneda $moneda_id
|
||||
*/
|
||||
class Transaccion extends Model {
|
||||
public static $_table = 'transacciones';
|
||||
protected static $fields = ['debito_id', 'credito_id', 'fecha', 'glosa', 'detalle', 'valor'];
|
||||
protected static $fields = ['debito_id', 'credito_id', 'fecha', 'glosa', 'detalle', 'valor', 'moneda_id'];
|
||||
|
||||
protected $debito;
|
||||
public function debito() {
|
||||
@ -37,6 +38,21 @@ class Transaccion extends Model {
|
||||
return Carbon::parse($this->fecha);
|
||||
}
|
||||
$this->fecha = $fecha->format('Y-m-d');
|
||||
return $this;
|
||||
}
|
||||
protected $moneda;
|
||||
public function moneda() {
|
||||
if ($this->moneda === null) {
|
||||
$this->moneda = $this->childOf(Moneda::class, [Model::SELF_KEY => 'moneda_id']);
|
||||
}
|
||||
return $this->moneda;
|
||||
}
|
||||
|
||||
public function transformar(Moneda $moneda = null) {
|
||||
if (($moneda !== null and $this->moneda()->id === $moneda->id) or ($moneda === null and $this->moneda()->id === 1)) {
|
||||
return $this->valor;
|
||||
}
|
||||
return $this->moneda()->cambiar($this->fecha(), $this->valor, $moneda);
|
||||
}
|
||||
|
||||
public function toArray(): array {
|
||||
|
12
console/Dockerfile
Normal file
12
console/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM php:8-cli
|
||||
|
||||
RUN apt-get update -y && apt-get install -y cron git libzip-dev zip
|
||||
|
||||
RUN docker-php-ext-install zip
|
||||
|
||||
COPY --from=composer /usr/bin/composer /usr/bin/composer
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
CMD ["cron", "-f", "-l", "2"]
|
||||
ENTRYPOINT ["cron", "-f", "-l", "2"]
|
7
console/bin/console
Normal file
7
console/bin/console
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
$app = require_once implode(DIRECTORY_SEPARATOR, [
|
||||
dirname(__FILE__, 2),
|
||||
'setup',
|
||||
'app.php'
|
||||
]);
|
||||
$app->run();
|
37
console/common/Command/Consolidar.php
Normal file
37
console/common/Command/Consolidar.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Command;
|
||||
|
||||
use Psr\Http\Client\ClientInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Consolidar extends Command {
|
||||
protected $client;
|
||||
public function __construct(ClientInterface $client = null, string $name = null) {
|
||||
parent::__construct($name);
|
||||
$this->setClient($client);
|
||||
}
|
||||
|
||||
public function setClient(ClientInterface $client) {
|
||||
$this->client = $client;
|
||||
return $this;
|
||||
}
|
||||
public function getClient(): ClientInterface {
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output) {
|
||||
try {
|
||||
$response = $this->getClient()->get('/consolidar');
|
||||
if ($response->getStatusCode() === 200) {
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
error_log($response->getReasonPhrase());
|
||||
return Command::FAILURE;
|
||||
} catch (\Exception $e) {
|
||||
error_log($e);
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
53
console/common/Command/Queue.php
Normal file
53
console/common/Command/Queue.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Command;
|
||||
|
||||
use Psr\Http\Client\ClientInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Queue extends Command {
|
||||
protected $client;
|
||||
public function __construct(ClientInterface $client = null, string $name = null) {
|
||||
parent::__construct($name);
|
||||
$this->setClient($client);
|
||||
}
|
||||
|
||||
public function setClient(ClientInterface $client) {
|
||||
$this->client = $client;
|
||||
return $this;
|
||||
}
|
||||
public function getClient(): ClientInterface {
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$response = $this->getClient()->get('/queues/pending');
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
return Command::FAILURE;
|
||||
}
|
||||
$data = json_decode($response->getBody()->getContents());
|
||||
$output = [
|
||||
'input' => $data,
|
||||
'processed' => []
|
||||
];
|
||||
foreach ($data->pending as $queue) {
|
||||
$log = "Running {$queue->command} from queue. Created in {$queue->created}.";
|
||||
error_log($log);
|
||||
$cmd = '/usr/local/bin/php /app/bin/console ' . $queue->cmd;
|
||||
exec($cmd, $result, $code);
|
||||
if ($code != Command::SUCCESS) {
|
||||
error_log(var_export($queue, true));
|
||||
error_log(var_export($result, true));
|
||||
continue;
|
||||
}
|
||||
$output['processed'] []= $queue->id;
|
||||
}
|
||||
$response = $this->getClient()->post('/queues/processed', ['json' => $output]);
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
return Command::FAILURE;
|
||||
}
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
38
console/common/Command/UpdateConsolidar.php
Normal file
38
console/common/Command/UpdateConsolidar.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Command;
|
||||
|
||||
use Psr\Http\Client\ClientInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class UpdateConsolidar extends Command {
|
||||
protected $client;
|
||||
public function __construct(ClientInterface $client = null, string $name = null) {
|
||||
parent::__construct($name);
|
||||
$this->setClient($client);
|
||||
}
|
||||
|
||||
public function setClient(ClientInterface $client) {
|
||||
$this->client = $client;
|
||||
return $this;
|
||||
}
|
||||
public function getClient(): ClientInterface {
|
||||
return $this->client;
|
||||
}
|
||||
public function execute(InputInterface $input, OutputInterface $output) {
|
||||
try {
|
||||
$mes = $input->getArgument('mes');
|
||||
$cuenta = $input->getArgument('cuenta');
|
||||
$response = $this->getClient()->get("/consolidar/update/{$mes}/{$cuenta}/");
|
||||
if ($response->getStatusCode() === 200) {
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
error_log($response->getReasonPhrase());
|
||||
return Command::FAILURE;
|
||||
} catch (\Exception $e) {
|
||||
error_log($e);
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
21
console/common/Define/Application.php
Normal file
21
console/common/Define/Application.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Define;
|
||||
|
||||
use Psr\Container\ContainerInterface as Container;
|
||||
use Symfony\Component\Console\Application as Base;
|
||||
|
||||
class Application extends Base {
|
||||
public function __construct(Container $container = null, string $name = 'UNKNOWN', string $version = 'UNKNOWN')
|
||||
{
|
||||
parent::__construct($name, $version);
|
||||
$this->setContainer($container);
|
||||
}
|
||||
protected $container;
|
||||
public function setContainer(Container $container) {
|
||||
$this->container = $container;
|
||||
return $this;
|
||||
}
|
||||
public function getContainer() {
|
||||
return $this->container;
|
||||
}
|
||||
}
|
25
console/composer.json
Normal file
25
console/composer.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "provm/contabilidad-console",
|
||||
"type": "project",
|
||||
"require": {
|
||||
"symfony/console": "^6.0",
|
||||
"php-di/php-di": "^6.3",
|
||||
"nesbot/carbon": "^2.57",
|
||||
"guzzlehttp/guzzle": "^7.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"kint-php/kint": "^4.1"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Aldarien",
|
||||
"email": "aldarien85@gmail.com"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Contabilidad\\Common\\": "common/"
|
||||
}
|
||||
}
|
||||
}
|
24
console/crontab
Normal file
24
console/crontab
Normal file
@ -0,0 +1,24 @@
|
||||
# Edit this file to introduce tasks to be run by cron.
|
||||
#
|
||||
# Each task to run has to be defined through a single line
|
||||
# indicating with different fields when the task will be run
|
||||
# and what command to run for the task
|
||||
#
|
||||
# To define the time you can provide concrete values for
|
||||
# minute (m), hour (h), day of month (dom), month (mon),
|
||||
# and day of week (dow) or use '*' in these fields (for 'any').
|
||||
#
|
||||
# Notice that tasks will be started based on the cron's system
|
||||
# daemon's notion of time and timezones.
|
||||
#
|
||||
# Output of the crontab jobs (including errors) is sent through
|
||||
# email to the user the crontab file belongs to (unless redirected).
|
||||
#
|
||||
# For example, you can run a backup of all your user accounts
|
||||
# at 5 a.m every week with:
|
||||
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
|
||||
#
|
||||
# For more information see the manual pages of crontab(5) and cron(8)
|
||||
#
|
||||
# m h dom mon dow command
|
||||
0 2 * * * /usr/local/bin/php /app/bin/console queue
|
4
console/php.ini
Normal file
4
console/php.ini
Normal file
@ -0,0 +1,4 @@
|
||||
[PHP]
|
||||
display_errors = E_ALL
|
||||
log_errors = true
|
||||
error_log = /var/log/php/error.log
|
39
console/setup/app.php
Normal file
39
console/setup/app.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
use DI\ContainerBuilder as Builder;
|
||||
use Contabilidad\Common\Define\Application;
|
||||
|
||||
require_once 'composer.php';
|
||||
|
||||
$builder = new Builder();
|
||||
$folders = [
|
||||
'settings',
|
||||
'setups'
|
||||
];
|
||||
foreach ($folders as $f) {
|
||||
$folder = implode(DIRECTORY_SEPARATOR, [__DIR__, $f]);
|
||||
if (!file_exists($folder)) {
|
||||
continue;
|
||||
}
|
||||
$files = new DirectoryIterator($folder);
|
||||
foreach ($files as $file) {
|
||||
if ($file->isDir()) {
|
||||
continue;
|
||||
}
|
||||
$builder->addDefinitions($file->getRealPath());
|
||||
}
|
||||
}
|
||||
$container = $builder->build();
|
||||
$app = new Application($container);
|
||||
|
||||
$folder = implode(DIRECTORY_SEPARATOR, [__DIR__, 'commands']);
|
||||
if (file_exists($folder)) {
|
||||
$files = new DirectoryIterator($folder);
|
||||
foreach ($files as $file) {
|
||||
if ($file->isDir() or $file->getExtension() != 'php') {
|
||||
continue;
|
||||
}
|
||||
include_once $file->getRealPath();
|
||||
}
|
||||
}
|
||||
|
||||
return $app;
|
4
console/setup/commands/01_queue.php
Normal file
4
console/setup/commands/01_queue.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Command\Queue;
|
||||
|
||||
$app->add(new Queue($app->getContainer()->get(\Psr\Http\Client\ClientInterface::class), 'queue'));
|
4
console/setup/commands/02_consolidar.php
Normal file
4
console/setup/commands/02_consolidar.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Command\Consolidar;
|
||||
|
||||
$app->add(new Consolidar($app->getContainer()->get(\Psr\Http\Client\ClientInterface::class), 'consolidar'));
|
4
console/setup/commands/03_update_consolidar.php
Normal file
4
console/setup/commands/03_update_consolidar.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Command\UpdateConsolidar;
|
||||
|
||||
$app->add(new UpdateConsolidar($app->getContainer()->get(\Psr\Http\Client\ClientInterface::class), 'update_consolidar'));
|
6
console/setup/composer.php
Normal file
6
console/setup/composer.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
require_once implode(DIRECTORY_SEPARATOR, [
|
||||
dirname(__DIR__),
|
||||
'vendor',
|
||||
'autoload.php'
|
||||
]);
|
5
console/setup/settings/02_api.php
Normal file
5
console/setup/settings/02_api.php
Normal file
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
return [
|
||||
'api_url' => $_ENV['API_URL'],
|
||||
'api_key' => $_ENV['API_KEY']
|
||||
];
|
13
console/setup/setups/02_client.php
Normal file
13
console/setup/setups/02_client.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
use Psr\Container\ContainerInterface as Container;
|
||||
|
||||
return [
|
||||
\Psr\Http\Client\ClientInterface::class => function(Container $container) {
|
||||
return new \GuzzleHttp\Client([
|
||||
'base_uri' => $container->get('api_url'),
|
||||
'headers' => [
|
||||
'Authorization' => "Bearer {$container->get('api_key')}"
|
||||
]
|
||||
]);
|
||||
}
|
||||
];
|
@ -1,15 +1,18 @@
|
||||
version: '3'
|
||||
|
||||
x-restart: &restart
|
||||
restart: unless-stopped
|
||||
|
||||
services:
|
||||
api:
|
||||
profiles:
|
||||
- api
|
||||
restart: unless-stopped
|
||||
<<: *restart
|
||||
image: php
|
||||
build:
|
||||
context: api
|
||||
env_file:
|
||||
- .env
|
||||
env_file:
|
||||
- .db.env
|
||||
- .api.env
|
||||
- .python.env
|
||||
volumes:
|
||||
@ -19,26 +22,26 @@ services:
|
||||
api-proxy:
|
||||
profiles:
|
||||
- api
|
||||
restart: unless-stopped
|
||||
<<: *restart
|
||||
image: nginx
|
||||
ports:
|
||||
- "9001:80"
|
||||
volumes:
|
||||
- ./api/nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
- ./logs/api/:/var/log/nginx/
|
||||
- ./logs/api/proxy/:/var/log/nginx/
|
||||
- ./api/:/app/
|
||||
db:
|
||||
profiles:
|
||||
- api
|
||||
restart: unless-stopped
|
||||
<<: *restart
|
||||
image: mariadb
|
||||
env_file: .env
|
||||
env_file: .db.env
|
||||
volumes:
|
||||
- contabilidad_data:/var/lib/mysql
|
||||
adminer:
|
||||
profiles:
|
||||
- api
|
||||
restart: unless-stopped
|
||||
<<: *restart
|
||||
image: adminer
|
||||
ports:
|
||||
- "9002:8080"
|
||||
@ -46,7 +49,7 @@ services:
|
||||
ui:
|
||||
profiles:
|
||||
- ui
|
||||
restart: unless-stopped
|
||||
<<: *restart
|
||||
image: php-ui
|
||||
env_file:
|
||||
- .api.env
|
||||
@ -60,19 +63,19 @@ services:
|
||||
ui-proxy:
|
||||
profiles:
|
||||
- ui
|
||||
restart: unless-stopped
|
||||
<<: *restart
|
||||
image: nginx
|
||||
ports:
|
||||
- "9000:80"
|
||||
volumes:
|
||||
- ./ui/nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
- ./logs/ui/:/var/log/nginx/
|
||||
- ./logs/ui/proxy/:/var/log/nginx/
|
||||
- ./ui/:/app/
|
||||
|
||||
python:
|
||||
profiles:
|
||||
- python
|
||||
restart: unless-stopped
|
||||
<<: *restart
|
||||
build:
|
||||
context: ./python
|
||||
env_file:
|
||||
@ -85,5 +88,21 @@ services:
|
||||
- ./api/public/uploads/pdfs/:/app/data/
|
||||
- ./logs/python/:/var/log/python/
|
||||
|
||||
console:
|
||||
profiles:
|
||||
- console
|
||||
<<: *restart
|
||||
build:
|
||||
context: ./console
|
||||
env_file:
|
||||
- .api.env
|
||||
- .console.env
|
||||
- .db.env
|
||||
volumes:
|
||||
- ./console/:/app/
|
||||
- ./console/php.ini:/usr/local/etc/php/conf.d/php.ini
|
||||
- ./logs/console/:/var/log/php/
|
||||
- ./console/crontab:/var/spool/cron/crontabs/root
|
||||
|
||||
volumes:
|
||||
contabilidad_data:
|
||||
|
@ -10,7 +10,8 @@ class Cuentas {
|
||||
return $view->render($response, 'cuentas.list');
|
||||
}
|
||||
public function show(Request $request, Response $response, View $view, $cuenta_id): Response {
|
||||
return $view->render($response, 'cuentas.show', compact('cuenta_id'));
|
||||
$max_transacciones = 100;
|
||||
return $view->render($response, 'cuentas.show', compact('cuenta_id', 'max_transacciones'));
|
||||
}
|
||||
public function add(Request $request, Response $response, View $view): Response {
|
||||
return $view->render($response, 'cuentas.add');
|
||||
|
13
ui/common/Controller/Queues.php
Normal file
13
ui/common/Controller/Queues.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace Contabilidad\Common\Controller;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Slim\Views\Blade as View;
|
||||
|
||||
class Queues
|
||||
{
|
||||
public function __invoke(Request $request, Response $response, View $view): Response {
|
||||
return $view->render($response, 'queues.list');
|
||||
}
|
||||
}
|
@ -5,11 +5,11 @@
|
||||
"require": {
|
||||
"php-di/php-di": "^6.3",
|
||||
"php-di/slim-bridge": "^3.1",
|
||||
"rubellum/slim-blade-view": "^0.1.1",
|
||||
"nyholm/psr7-server": "^1.0",
|
||||
"zeuxisoo/slim-whoops": "^0.7.3",
|
||||
"nyholm/psr7": "^1.4",
|
||||
"guzzlehttp/guzzle": "^7.4"
|
||||
"guzzlehttp/guzzle": "^7.4",
|
||||
"berrnd/slim-blade-view": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5",
|
||||
|
@ -1,5 +1,5 @@
|
||||
class Transaccion {
|
||||
constructor({id, debito_id, credito_id, fecha, glosa, detalle, valor, debito, credito, fechaFormateada, valorFormateado}) {
|
||||
constructor({id, debito_id, credito_id, fecha, glosa, detalle, valor, debito, credito, fechaFormateada, valorFormateado, format, moneda_id}) {
|
||||
this.id = id
|
||||
this.debito_id = debito_id
|
||||
this.credito_id = credito_id
|
||||
@ -13,6 +13,7 @@ class Transaccion {
|
||||
valor,
|
||||
formateado: valorFormateado
|
||||
}
|
||||
this.format_array = format
|
||||
this.debito = debito
|
||||
this.credito = credito
|
||||
this.modal = null
|
||||
@ -33,7 +34,7 @@ class Transaccion {
|
||||
}
|
||||
return !this.isDebito()
|
||||
}
|
||||
draw({saldo, format}) {
|
||||
draw({saldo, format, format_array, format_call}) {
|
||||
const fuente = (this.isDebito()) ? this.credito : this.debito
|
||||
return $('<tr></tr>').append(
|
||||
$('<td></td>').html(this.fecha.formateada)
|
||||
@ -44,11 +45,11 @@ class Transaccion {
|
||||
).append(
|
||||
$('<td></td>').html(this.glosa + '<br />' + this.detalle)
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').html((this.isIncrement()) ? '' : format.format(this.valor.valor))
|
||||
$('<td></td>').attr('class', 'right aligned').html((this.isIncrement()) ? '' : format_call({value: this.valor.valor, format, format_array}))
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').html((this.isIncrement()) ? format.format(this.valor.valor) : '')
|
||||
$('<td></td>').attr('class', 'right aligned').html((this.isIncrement()) ? format_call({value: -this.valor.valor, format, format_array}) : '')
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').html(format.format(saldo))
|
||||
$('<td></td>').attr('class', 'right aligned').html(format_call({value: saldo, format_array, format}))
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').append(
|
||||
$('<button></button>').attr('class', 'ui tiny circular icon button').append(
|
||||
@ -90,11 +91,35 @@ class Transaccion {
|
||||
|
||||
const transacciones = {
|
||||
id: '#transacciones',
|
||||
mes: '#mes',
|
||||
buttons: {
|
||||
prev: '#prev_button',
|
||||
left: '#left_button',
|
||||
today: '#today_button',
|
||||
right: '#right_button',
|
||||
next: '#next_button'
|
||||
},
|
||||
cuenta_id: 0,
|
||||
cuenta: null,
|
||||
transacciones: [],
|
||||
cuentas: [],
|
||||
monedas: [],
|
||||
date: new Date(),
|
||||
saldo: 0,
|
||||
acumulation: 0,
|
||||
intl_format: null,
|
||||
max: null,
|
||||
format: ({format_array, format, value}) => {
|
||||
let output = []
|
||||
if (format_array.prefijo !== '') {
|
||||
output.push(format_array.prefijo)
|
||||
}
|
||||
output.push(format.format(Math.round(value * Math.pow(10, format_array.decimales)) / Math.pow(10, format_array.decimales)))
|
||||
if (format_array.sufijo !== '') {
|
||||
output.push(format_array.sufijo)
|
||||
}
|
||||
return output.join('')
|
||||
},
|
||||
get: function() {
|
||||
return {
|
||||
transacciones: () => {
|
||||
@ -105,20 +130,14 @@ const transacciones = {
|
||||
return
|
||||
}
|
||||
this.cuenta = data.cuenta
|
||||
this.intl_format = Intl.NumberFormat('es-CL')
|
||||
sendGet(_urls.api + '/cuenta/' + this.cuenta_id + '/categoria').then((resp) => {
|
||||
this.cuenta.categoria = resp.categoria
|
||||
}).then(() => {
|
||||
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)
|
||||
)
|
||||
}
|
||||
promises = this.get().transaccionesMes(this.date)
|
||||
if (promises.length > 0) {
|
||||
Promise.all(promises).then((data_arr) => {
|
||||
this.transacciones = []
|
||||
@ -137,7 +156,13 @@ const transacciones = {
|
||||
return (new Date(b.fecha)) - (new Date(a.fecha))
|
||||
})
|
||||
}).then(() => {
|
||||
this.draw().table()
|
||||
this.get().transaccionesAcumulacion(this.date).then((response) => {
|
||||
this.acumulation = response.acumulation
|
||||
this.saldo = response.acumulation
|
||||
}).then(() => {
|
||||
this.draw().table()
|
||||
this.draw().acumulation()
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.draw().table()
|
||||
@ -145,6 +170,32 @@ const transacciones = {
|
||||
})
|
||||
})
|
||||
},
|
||||
transaccionesLimit: () => {
|
||||
let promises = []
|
||||
const amount = data.transacciones
|
||||
let step = 50
|
||||
let start = 0
|
||||
if (this.max !== null) {
|
||||
step = Math.min(50, this.max)
|
||||
start = Math.max(0, amount - this.max)
|
||||
}
|
||||
for (let i = start; i <= amount; i += step) {
|
||||
promises.push(
|
||||
sendGet(_urls.api + '/cuenta/' + this.cuenta_id + '/transacciones/' + step + '/' + i)
|
||||
)
|
||||
}
|
||||
return promises
|
||||
},
|
||||
transaccionesMes: (mes) => {
|
||||
let promises = []
|
||||
promises.push(
|
||||
sendGet(_urls.api + '/cuenta/' + this.cuenta_id + '/transacciones/month/' + [mes.getFullYear(), mes.getMonth() + 1, '1'].join('-'))
|
||||
)
|
||||
return promises
|
||||
},
|
||||
transaccionesAcumulacion: (mes) => {
|
||||
return sendGet(_urls.api + '/cuenta/' + this.cuenta_id + '/transacciones/acum/' + [mes.getFullYear(), mes.getMonth() + 1, '1'].join('-'))
|
||||
},
|
||||
cuentas: () => {
|
||||
return sendGet(_urls.api + '/cuentas').then((data) => {
|
||||
if (data.cuentas === null || data.cuentas.length === 0) {
|
||||
@ -158,6 +209,17 @@ const transacciones = {
|
||||
select.append(
|
||||
$('<option></option>').attr('value', el.id).html(el.nombre + ' (' + el.categoria.nombre + ')')
|
||||
)
|
||||
select.dropdown()
|
||||
})
|
||||
})
|
||||
this.get().monedas().then(() => {
|
||||
const select = this.modal.find("[name='moneda']")
|
||||
$.each(this.monedas, (i, el) => {
|
||||
const option = $('<option></option>').attr('value', el.id).html(el.denominacion)
|
||||
if (el.id === '1') {
|
||||
option.attr('selected', 'selected')
|
||||
}
|
||||
select.append(option)
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -166,6 +228,11 @@ const transacciones = {
|
||||
return sendGet(_urls.api + '/cuenta/' + this.cuentas[idx].id + '/categoria').then((data) => {
|
||||
this.cuentas[idx].categoria = data.categoria
|
||||
})
|
||||
},
|
||||
monedas: () => {
|
||||
return sendGet(_urls.api + '/monedas').then((response) => {
|
||||
this.monedas = response.monedas
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -185,13 +252,36 @@ const transacciones = {
|
||||
)
|
||||
},
|
||||
table: () => {
|
||||
const format = Intl.NumberFormat('es-CL', {style: 'currency', currency: this.cuenta.moneda.codigo})
|
||||
const parent = $(this.id)
|
||||
parent.html('')
|
||||
$.each(this.transacciones, (i, el) => {
|
||||
parent.append(el.draw({saldo: this.saldo, format: format}))
|
||||
this.saldo = this.saldo + parseInt(el.valor.valor) * ((el.isIncrement()) ? 1 : -1)
|
||||
this.saldo = this.saldo + parseInt(el.valor.valor)// * ((el.isIncrement()) ? 1 : -1)
|
||||
parent.append(el.draw({saldo: this.saldo, format: this.intl_format, format_array: this.cuenta.moneda.format, format_call: this.format}))
|
||||
})
|
||||
},
|
||||
acumulation: () => {
|
||||
const parent = $(this.id)
|
||||
parent.prepend(
|
||||
$('<tr></tr>').append(
|
||||
$('<td></td>').html('')
|
||||
).append(
|
||||
$('<td></td>').html('')
|
||||
).append(
|
||||
$('<td></td>').html('Acumulacion Anterior')
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').html('')
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').html('')
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').html(this.format({
|
||||
format_array: this.cuenta.moneda.format,
|
||||
format: this.intl_format,
|
||||
value: this.acumulation
|
||||
}))
|
||||
).append(
|
||||
$('<td></td>').attr('class', 'right aligned').html('')
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -199,17 +289,11 @@ const transacciones = {
|
||||
return {
|
||||
show: () => {
|
||||
this.modal.find('form').trigger('reset')
|
||||
modalToAdd(this.modal)
|
||||
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()
|
||||
})
|
||||
sendPost(_urls.api + '/tipos/cambios/add', data1)
|
||||
|
||||
const valor = $("[name='valor']").val()
|
||||
const cuenta = $("[name='cuenta']").val()
|
||||
@ -219,7 +303,8 @@ const transacciones = {
|
||||
fecha: fecha,
|
||||
glosa: $("[name='glosa']").val(),
|
||||
detalle: $("[name='detalle']").val(),
|
||||
valor: (valor < 0) ? -valor : valor
|
||||
valor: (valor < 0) ? -valor : valor,
|
||||
moneda_id: $("[name='moneda']").val()
|
||||
})
|
||||
return sendPost(_urls.api + '/transacciones/add', data).then(() => {
|
||||
this.modal.modal('hide')
|
||||
@ -235,21 +320,61 @@ const transacciones = {
|
||||
const glosa = $("[name='glosa']").val()
|
||||
const detalle = $("[name='detalle']").val()
|
||||
const valor = $("[name='valor']").val()
|
||||
const moneda_id = $("[name='moneda']").val()
|
||||
const data = JSON.stringify({
|
||||
debito_id: (valor < 0) ? this.cuenta_id : cuenta,
|
||||
credito_id: (valor < 0) ? cuenta : this.cuenta_id,
|
||||
fecha,
|
||||
glosa,
|
||||
detalle,
|
||||
valor: (valor < 0) ? -valor : valor
|
||||
valor: (valor < 0) ? -valor : valor,
|
||||
moneda_id
|
||||
})
|
||||
return sendPut(_urls.api + '/transaccion/' + id + '/edit', data).then(() => {
|
||||
this.modal.modal('hide')
|
||||
this.get().transacciones()
|
||||
})
|
||||
},
|
||||
changeMonth: function(dif) {
|
||||
let d = this.date
|
||||
d.setMonth(this.date.getMonth() + dif)
|
||||
this.date = d
|
||||
this.checkButtons()
|
||||
$(this.mes).calendar('set date', this.date)
|
||||
},
|
||||
today: function() {
|
||||
this.date = new Date()
|
||||
this.checkButtons()
|
||||
$(this.mes).calendar('set date', this.date)
|
||||
},
|
||||
changeYear: function(dif) {
|
||||
let d = this.date
|
||||
d.setFullYear(this.date.getFullYear() + dif)
|
||||
this.date = d
|
||||
this.checkButtons()
|
||||
$(this.mes).calendar('set date', this.date)
|
||||
},
|
||||
checkButtons: function() {
|
||||
let f = new Date()
|
||||
if (this.date.getMonth() === f.getMonth() && this.date.getFullYear() === f.getFullYear()) {
|
||||
$(this.buttons.right).addClass('disabled')
|
||||
} else {
|
||||
$(this.buttons.right).removeClass('disabled')
|
||||
}
|
||||
if (this.date.toDateString() === f.toDateString()) {
|
||||
$(this.buttons.today).addClass('disabled')
|
||||
} else {
|
||||
$(this.buttons.today).removeClass('disabled')
|
||||
}
|
||||
if (this.date.getFullYear() === f.getFullYear()) {
|
||||
$(this.buttons.next).addClass('disabled')
|
||||
} else {
|
||||
$(this.buttons.next).removeClass('disabled')
|
||||
}
|
||||
},
|
||||
refresh: function () {
|
||||
this.get().transacciones()
|
||||
this.checkButtons()
|
||||
},
|
||||
build: function() {
|
||||
return {
|
||||
@ -283,11 +408,52 @@ const transacciones = {
|
||||
maxDate: new Date()
|
||||
})
|
||||
this.get().cuentas()
|
||||
},
|
||||
mes: () => {
|
||||
const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Dicembre']
|
||||
$(this.mes).calendar({
|
||||
type: 'month',
|
||||
initialDate: this.date,
|
||||
maxDate: new Date(),
|
||||
text: {
|
||||
months: meses,
|
||||
monthsShort: meses.map((item) => {item.slice(0, 3)})
|
||||
},
|
||||
formatter: {
|
||||
date: function (date, settings) {
|
||||
if (!date) return '';
|
||||
return meses[date.getMonth()] + ', ' + date.getFullYear()
|
||||
}
|
||||
},
|
||||
onChange: (date) => {
|
||||
this.date = date
|
||||
this.refresh()
|
||||
}
|
||||
})
|
||||
},
|
||||
buttons: () => {
|
||||
$(this.buttons.today).click((e) => {
|
||||
this.today()
|
||||
})
|
||||
$(this.buttons.right).click((e) => {
|
||||
this.changeMonth(1)
|
||||
})
|
||||
$(this.buttons.left).click((e) => {
|
||||
this.changeMonth(-1)
|
||||
})
|
||||
$(this.buttons.next).click(() => {
|
||||
this.changeYear(1)
|
||||
})
|
||||
$(this.buttons.prev).click(() => {
|
||||
this.changeYear(-1)
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
setup: function() {
|
||||
this.build().modal()
|
||||
this.build().mes()
|
||||
this.build().buttons()
|
||||
$(this.id).parent().find('#refresh').click(() => {
|
||||
this.refresh()
|
||||
})
|
@ -59,15 +59,12 @@ class Cuenta {
|
||||
}
|
||||
}
|
||||
class Categoria {
|
||||
constructor({id, nombre, tipo_id, tipo, activos, pasivos, ganancias, perdidas}) {
|
||||
constructor({id, nombre, tipo_id, tipo, totales}) {
|
||||
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.totales = totales
|
||||
this.is_open = false
|
||||
this.cuentas = []
|
||||
}
|
||||
@ -75,7 +72,7 @@ class Categoria {
|
||||
this.tipos = tipos
|
||||
}
|
||||
draw({format}) {
|
||||
const button = $('<button></button>').attr('class', 'ui mini compact icon button').append(
|
||||
const button = $('<button></button>').attr('class', 'ui mini compact circular icon button').append(
|
||||
$('<i></i>').attr('class', down_icon + ' icon')
|
||||
).click((e) => {
|
||||
const plus = button.find('.' + down_icon.replace(' ', '.') + '.icon')
|
||||
@ -98,7 +95,7 @@ class Categoria {
|
||||
)
|
||||
$.each(this.tipos, (i, el) => {
|
||||
tr.append(
|
||||
$('<td></td>').attr('class', 'right aligned').html(format.format(this[el.descripcion.toLowerCase() + 's']))
|
||||
$('<td></td>').attr('class', 'right aligned').html(format.format(this.totales[el.descripcion.toLowerCase() + 's']))
|
||||
)
|
||||
})
|
||||
$("[data-id='" + this.tipo_id + "'][data-class='tipo_categoria']").after(tr)
|
||||
@ -156,21 +153,18 @@ class Categoria {
|
||||
}
|
||||
}
|
||||
class TipoCategoria {
|
||||
constructor({id, descripcion, activo, activos, pasivos, ganancias, perdidas}) {
|
||||
constructor({id, descripcion, activo, totales}) {
|
||||
this.id = id
|
||||
this.descripcion = descripcion
|
||||
this.activo = activo
|
||||
this.activos = activos
|
||||
this.pasivos = pasivos
|
||||
this.ganancias = ganancias
|
||||
this.perdidas = perdidas
|
||||
this.totales = totales
|
||||
this.categorias = []
|
||||
}
|
||||
setTipos(tipos) {
|
||||
this.tipos = tipos
|
||||
}
|
||||
draw({format}) {
|
||||
const button = $('<button></button>').attr('class', 'ui mini compact icon button').append(
|
||||
const button = $('<button></button>').attr('class', 'ui mini compact circular icon button').append(
|
||||
$('<i></i>').attr('class', down_icon + ' icon')
|
||||
).click((e) => {
|
||||
const plus = button.find('.' + down_icon.replace(' ', '.') + '.icon')
|
||||
@ -188,7 +182,7 @@ class TipoCategoria {
|
||||
)
|
||||
)
|
||||
$.each(this.tipos, (i, el) => {
|
||||
tr.append($('<td></td>').attr('class', 'right aligned').html(format.format(this[el.descripcion.toLowerCase() + 's'])))
|
||||
tr.append($('<td></td>').attr('class', 'right aligned').html(format.format(this.totales[el.descripcion.toLowerCase() + 's'])))
|
||||
})
|
||||
return tr
|
||||
}
|
||||
@ -295,7 +289,7 @@ const cuentas = {
|
||||
return
|
||||
}
|
||||
$.each(data.tipos, (i, el) => {
|
||||
tipo = new TipoCategoria(el)
|
||||
const tipo = new TipoCategoria(el)
|
||||
tipo.setTipos(this.tipos)
|
||||
this.tipos_categorias.push(tipo)
|
||||
})
|
||||
|
@ -1,7 +1,12 @@
|
||||
<?php
|
||||
require_once implode(DIRECTORY_SEPARATOR, [
|
||||
dirname(__DIR__),
|
||||
'setup',
|
||||
'app.php'
|
||||
]);
|
||||
$app->run();
|
||||
try {
|
||||
require_once implode(DIRECTORY_SEPARATOR, [
|
||||
dirname(__DIR__),
|
||||
'setup',
|
||||
'app.php'
|
||||
]);
|
||||
$app->run();
|
||||
} catch (Error | Exception $e) {
|
||||
error_log($e);
|
||||
throw $e;
|
||||
}
|
||||
|
6
ui/resources/routes/queues.php
Normal file
6
ui/resources/routes/queues.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
use Contabilidad\Common\Controller\Queues;
|
||||
|
||||
$app->group('/queues', function($app) {
|
||||
$app->get('[/]', Queues::class);
|
||||
});
|
@ -28,7 +28,7 @@
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script type="text/javascript" src="{{$urls->scripts}}/categorias.list.js"></script>
|
||||
<script type="text/javascript" src="{{$urls->scripts}}/categorias/list.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(() => {
|
||||
categorias.setup()
|
||||
|
@ -24,7 +24,7 @@
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script type="text/javascript" src="{{$urls->scripts}}/tipos_categorias.list.js"></script>
|
||||
<script type="text/javascript" src="{{$urls->scripts}}/categorias/tipos/list.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(() => {
|
||||
tipos_categorias.setup()
|
||||
|
@ -2,4 +2,5 @@
|
||||
@include('config.menu.tipos_categorias')
|
||||
@include('config.menu.tipos_cuentas')
|
||||
@include('config.menu.files')
|
||||
@include('config.menu.queues')
|
||||
</div>
|
||||
|
3
ui/resources/views/config/menu/queues.blade.php
Normal file
3
ui/resources/views/config/menu/queues.blade.php
Normal file
@ -0,0 +1,3 @@
|
||||
<a class="item" href="{{$urls->base}}queues">
|
||||
Queues
|
||||
</a>
|
@ -32,7 +32,7 @@
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script type="text/javascript" src="{{$urls->scripts}}/cuentas.list.js"></script>
|
||||
<script type="text/javascript" src="{{$urls->scripts}}/cuentas/list.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(() => {
|
||||
cuentas.setup()
|
||||
|
@ -5,6 +5,29 @@
|
||||
@endsection
|
||||
|
||||
@section('cuentas_content')
|
||||
<div class="ui right aligned header">
|
||||
<div class="ui calendar" id="mes">
|
||||
<div class="ui input right icon">
|
||||
<input type="text" placeholder="Mes" />
|
||||
<i class="calendar icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui icon button" id="prev_button">
|
||||
<i class="double left angle icon"></i>
|
||||
</div>
|
||||
<div class="ui icon button" id="left_button">
|
||||
<i class="left angle icon"></i>
|
||||
</div>
|
||||
<div class="ui icon disabled button" id="today_button">
|
||||
<i class="calendar day icon"></i>
|
||||
</div>
|
||||
<div class="ui icon disabled button" id="right_button">
|
||||
<i class="right angle icon"></i>
|
||||
</div>
|
||||
<div class="ui icon disabled button" id="next_button">
|
||||
<i class="double right angle icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
<table class="ui striped table">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -55,7 +78,7 @@
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Cuenta</label>
|
||||
<select name="cuenta"></select>
|
||||
<select name="cuenta" class="ui searchable dropdown"></select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Glosa</label>
|
||||
@ -65,9 +88,15 @@
|
||||
<label>Detalle</label>
|
||||
<input type="text" name="detalle" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Valor</label>
|
||||
<input type="text" name="valor" />
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
<label>Valor</label>
|
||||
<input type="text" name="valor" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<lable>Moneda</lable>
|
||||
<select name="moneda"></select>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui icon button">
|
||||
<i class="plus icon"></i>
|
||||
@ -78,10 +107,11 @@
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script type="text/javascript" src="{{$urls->scripts}}/cuentas.show.js"></script>
|
||||
<script type="text/javascript" src="{{$urls->scripts}}/cuentas/show.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(() => {
|
||||
transacciones.cuenta_id = {{$cuenta_id}}
|
||||
transacciones.max = {{$max_transacciones ?? 100}}
|
||||
transacciones.setup()
|
||||
})
|
||||
</script>
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
@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" src="{{$urls->scripts}}/cuentas/tipos/list.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(() => {
|
||||
tipos_cuentas.setup()
|
||||
|
8
ui/resources/views/queues/base.blade.php
Normal file
8
ui/resources/views/queues/base.blade.php
Normal file
@ -0,0 +1,8 @@
|
||||
@extends('config.base')
|
||||
|
||||
@section('config_content')
|
||||
<h1 class="ui header">Queues</h1>
|
||||
<div class="ui basic fitted segment">
|
||||
@yield('queues_content')
|
||||
</div>
|
||||
@endsection
|
38
ui/resources/views/queues/list.blade.php
Normal file
38
ui/resources/views/queues/list.blade.php
Normal file
@ -0,0 +1,38 @@
|
||||
@extends('queues.base')
|
||||
|
||||
@section('queues_content')
|
||||
<table class="ui table" id="queues">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Comando</th>
|
||||
<th>Creado</th>
|
||||
<!-- <th class="right aligned">
|
||||
Procesar
|
||||
<button class="ui tiny circular icon button" id="procesar">
|
||||
<i class="green play icon"></i>
|
||||
</button>
|
||||
</th> -->
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script type="text/javascript">
|
||||
$(document).ready(() => {
|
||||
sendGet(_urls.api + '/queues/pending').then((response) => {
|
||||
const table = $('#queues')
|
||||
const tbody = $('<tbody></tbody>')
|
||||
response.pending.forEach((el, i) => {
|
||||
const row = $('<tr></tr>').append(
|
||||
$('<td></td>').html(el.command)
|
||||
).append(
|
||||
$('<td></td>').html(el.created)
|
||||
)
|
||||
tbody.append(row)
|
||||
})
|
||||
table.append(tbody)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@endpush
|
@ -61,7 +61,7 @@
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script type="text/javascript" src="{{$urls->scripts}}/uploads.list.js"></script>
|
||||
<script type="text/javascript" src="{{$urls->scripts}}/uploads/list.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(() => {
|
||||
archivos.setup()
|
||||
|
@ -22,5 +22,6 @@ return [
|
||||
]);
|
||||
$arr['api'] = $_ENV['API_URL'] ?? 'http://localhost:9001';
|
||||
return (object) $arr;
|
||||
}
|
||||
},
|
||||
'max_transacciones' => 100
|
||||
];
|
||||
|
Reference in New Issue
Block a user