diff --git a/api/common/Controller/Consolidados.php b/api/common/Controller/Consolidados.php index 5940570..872f93b 100644 --- a/api/common/Controller/Consolidados.php +++ b/api/common/Controller/Consolidados.php @@ -1,11 +1,13 @@ 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, []); + } } diff --git a/api/common/Controller/Transacciones.php b/api/common/Controller/Transacciones.php index 5dc6eec..fb3ecf5 100644 --- a/api/common/Controller/Transacciones.php +++ b/api/common/Controller/Transacciones.php @@ -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 = [ diff --git a/api/common/Service/Consolidar.php b/api/common/Service/Consolidar.php index 427eae4..566e7a2 100644 --- a/api/common/Service/Consolidar.php +++ b/api/common/Service/Consolidar.php @@ -2,7 +2,6 @@ namespace Contabilidad\Common\Service; use Carbon\Carbon; -use Contabilidad\Queue; use \Model; use ProVM\Common\Factory\Model as ModelFactory; use Contabilidad\Consolidado; @@ -10,9 +9,19 @@ use Contabilidad\Cuenta; use Contabilidad\Transaccion; class Consolidar { - protected $factory; - public function __construct(ModelFactory $factory) { + 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() { @@ -40,12 +49,7 @@ class Consolidar { return true; } public function queue() { - $data = [ - 'command' => 'consolidar', - 'created' => Carbon::now()->format('Y-m-d H:i:s') - ]; - $queue = Queue::add($this->factory, $data); - $queue->save(); + $this->queuer->queue('consolidar'); } public function consolidar() { ini_set('max_execution_time', 60*5); @@ -57,29 +61,40 @@ class Consolidar { $first = $this->getFirst($cuenta); $last = $this->getLast($cuenta); for ($current = $first->copy()->startOfMonth(); $current < $last->copy()->addMonthWithoutOverflow()->endOfMonth(); $current = $current->copy()->addMonthWithoutOverflow()) { - $transacciones = $this->getTransacciones($cuenta, $current); - if (count($transacciones) == 0) { - continue; - } - $f = $this->factory; - array_walk($transacciones, function(&$item) use ($cuenta, $f) { - $item->setFactory($f); - $item->valor = $item->transformar($cuenta->moneda()); - }); - $saldo = array_reduce($transacciones, function($sum, $item) { - return $sum + $item->valor; - }); - $data = [ - 'cuenta_id' => $cuenta->id, - 'fecha' => $current->format('Y-m-1'), - 'periodo' => 'P1M', - 'saldo' => $saldo - ]; - $consolidado = $this->factory->create(Consolidado::class, $data); - $consolidado->save(); + $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) @@ -150,6 +165,10 @@ class Consolidar { ->whereEqual('credito_id', $cuenta->id) ->whereRaw("fecha BETWEEN '{$start->format('Y-m-d')}' AND '{$end->format('Y-m-d')}'") ->findMany(); - return array_merge($debitos, $creditos); + $transacciones = array_merge($debitos, $creditos); + foreach ($transacciones as &$transaccion) { + $transaccion->setFactory($this->factory); + } + return $transacciones; } } diff --git a/api/common/Service/Queuer.php b/api/common/Service/Queuer.php new file mode 100644 index 0000000..51f12c0 --- /dev/null +++ b/api/common/Service/Queuer.php @@ -0,0 +1,47 @@ +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; + } +} \ No newline at end of file diff --git a/api/resources/routes/consolidar.php b/api/resources/routes/consolidar.php index e49c0ba..ab63298 100644 --- a/api/resources/routes/consolidar.php +++ b/api/resources/routes/consolidar.php @@ -1,4 +1,7 @@ get('/consolidar', [Consolidados::class, 'cli']); +$app->group('/consolidar', function($app) { + $app->get('/update/{mes}/{cuenta_id}', [Consolidados::class, 'update']); + $app->get('[/]', [Consolidados::class, 'cli']); +}); diff --git a/api/resources/routes/transacciones.php b/api/resources/routes/transacciones.php index 53b73c6..60a7437 100644 --- a/api/resources/routes/transacciones.php +++ b/api/resources/routes/transacciones.php @@ -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']); }); diff --git a/api/setup/setups/03_consolidar.php b/api/setup/setups/03_consolidar.php index b7c7bb8..a02b6e7 100644 --- a/api/setup/setups/03_consolidar.php +++ b/api/setup/setups/03_consolidar.php @@ -2,7 +2,10 @@ 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)); + return new \Contabilidad\Common\Service\Consolidar($container->get(\ProVM\Common\Factory\Model::class), $container->get(\Contabilidad\Common\Service\Queuer::class)); } ]; diff --git a/api/src/Cuenta.php b/api/src/Cuenta.php index 96a1277..29db250 100644 --- a/api/src/Cuenta.php +++ b/api/src/Cuenta.php @@ -59,32 +59,50 @@ class Cuenta extends Model { } return $this->consolidados; } - public function hasConsolidados(): bool { + public function hasConsolidados(\DateTimeInterface $mes = null): bool { $t = Carbon::now(); - return (bool) Model::factory(Consolidado::class) - ->whereEqual('cuenta_id', $this->id) - ->count('id'); + $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(): bool { + public function hasConsolidadosPending(\DateTimeInterface $mes = null): bool { $t = Carbon::now(); - return !(bool) Model::factory(Consolidado::class) + $q = Model::factory(Consolidado::class) ->whereEqual('cuenta_id', $this->id) - ->whereGte('fecha', $t->copy()->subMonthNoOverflow()->startOfMonth()->format('Y-m-d')) + ->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(): bool { - return (bool) Model::factory(Transaccion::class) + 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) - ->count('transacciones.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 ($transaccion->debito_id === $this->id) { - $transaccion->valor = - $transaccion->valor; + 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; diff --git a/api/src/Queue.php b/api/src/Queue.php index 36d018b..68de890 100644 --- a/api/src/Queue.php +++ b/api/src/Queue.php @@ -23,7 +23,7 @@ class Queue extends Model { $this->created = $fecha->format('Y-m-d H:i:s'); return $this; } - public function hasArguments() { + public function hasArguments(): bool { return Model::factory(QueueArgument::class) ->whereEqual('queue_id', $this->id) ->groupBy('queue_id') @@ -36,10 +36,25 @@ class Queue extends Model { } return $this->arguments; } - public function isProcessed() { + 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) { + public function setProcessed(bool $processed): Queue { $this->processed = $processed ? 1 : 0; return $this; } diff --git a/api/src/QueueArgument.php b/api/src/QueueArgument.php index e090c26..56670a6 100644 --- a/api/src/QueueArgument.php +++ b/api/src/QueueArgument.php @@ -21,6 +21,6 @@ class QueueArgument extends Model { } public function __toString(): string { - return "{$this->argument}='{$this->value}'"; + return "--{$this->argument} '{$this->value}'"; } } diff --git a/api/src/TipoCuenta.php b/api/src/TipoCuenta.php index 5ff4961..1b11eb5 100644 --- a/api/src/TipoCuenta.php +++ b/api/src/TipoCuenta.php @@ -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; + } } diff --git a/console/common/Command/Queue.php b/console/common/Command/Queue.php index 847502c..2cdef62 100644 --- a/console/common/Command/Queue.php +++ b/console/common/Command/Queue.php @@ -27,12 +27,12 @@ class Queue extends Command { if ($response->getStatusCode() !== 200) { return Command::FAILURE; } - $input = json_decode($response->getBody()->getContents()); + $data = json_decode($response->getBody()->getContents()); $output = [ - 'input' => $input, + 'input' => $data, 'processed' => [] ]; - foreach ($input->pending as $queue) { + 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; diff --git a/console/common/Command/UpdateConsolidar.php b/console/common/Command/UpdateConsolidar.php new file mode 100644 index 0000000..72a4913 --- /dev/null +++ b/console/common/Command/UpdateConsolidar.php @@ -0,0 +1,38 @@ +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; + } + } +} \ No newline at end of file diff --git a/ui/common/Controller/Queues.php b/ui/common/Controller/Queues.php new file mode 100644 index 0000000..f38ccd9 --- /dev/null +++ b/ui/common/Controller/Queues.php @@ -0,0 +1,13 @@ +render($response, 'queues.list'); + } +} \ No newline at end of file diff --git a/ui/resources/routes/queues.php b/ui/resources/routes/queues.php new file mode 100644 index 0000000..4b34307 --- /dev/null +++ b/ui/resources/routes/queues.php @@ -0,0 +1,6 @@ +group('/queues', function($app) { + $app->get('[/]', Queues::class); +}); \ No newline at end of file diff --git a/ui/resources/views/config/menu.blade.php b/ui/resources/views/config/menu.blade.php index 6137067..e57f083 100644 --- a/ui/resources/views/config/menu.blade.php +++ b/ui/resources/views/config/menu.blade.php @@ -2,4 +2,5 @@ @include('config.menu.tipos_categorias') @include('config.menu.tipos_cuentas') @include('config.menu.files') + @include('config.menu.queues') diff --git a/ui/resources/views/config/menu/queues.blade.php b/ui/resources/views/config/menu/queues.blade.php new file mode 100644 index 0000000..14586c4 --- /dev/null +++ b/ui/resources/views/config/menu/queues.blade.php @@ -0,0 +1,3 @@ + + Queues + \ No newline at end of file diff --git a/ui/resources/views/queues/base.blade.php b/ui/resources/views/queues/base.blade.php new file mode 100644 index 0000000..159ce9d --- /dev/null +++ b/ui/resources/views/queues/base.blade.php @@ -0,0 +1,8 @@ +@extends('config.base') + +@section('config_content') +

Queues

+
+ @yield('queues_content') +
+@endsection \ No newline at end of file diff --git a/ui/resources/views/queues/list.blade.php b/ui/resources/views/queues/list.blade.php new file mode 100644 index 0000000..1bd59f1 --- /dev/null +++ b/ui/resources/views/queues/list.blade.php @@ -0,0 +1,38 @@ +@extends('queues.base') + +@section('queues_content') + + + + + + + + +
ComandoCreado
+@endsection + +@push('scripts') + +@endpush \ No newline at end of file