API Movimientos y cartola diaria

This commit is contained in:
Juan Pablo Vial
2024-02-07 23:48:31 -03:00
parent 3cd699d2e2
commit 38962cb9cf
11 changed files with 307 additions and 9 deletions

View File

@ -2,9 +2,10 @@
namespace Incoviba\Common\Ideal\Cartola; namespace Incoviba\Common\Ideal\Cartola;
use Incoviba\Common\Define; use Incoviba\Common\Define;
use Incoviba\Common\Ideal\Service;
use Psr\Http\Message\UploadedFileInterface; use Psr\Http\Message\UploadedFileInterface;
abstract class Banco implements Define\Cartola\Banco abstract class Banco extends Service implements Define\Cartola\Banco
{ {
public function process(UploadedFileInterface $file): array public function process(UploadedFileInterface $file): array
{ {
@ -14,6 +15,9 @@ abstract class Banco implements Define\Cartola\Banco
foreach ($data as $row) { foreach ($data as $row) {
$r = []; $r = [];
foreach ($columns as $old => $new) { foreach ($columns as $old => $new) {
if (!isset($row[$old])) {
continue;
}
$r[$new] = $row[$old]; $r[$new] = $row[$old];
} }
$temp []= $r; $temp []= $r;

View File

@ -5,5 +5,8 @@ $app->group('/cartolas', function($app) {
$app->post('/procesar[/]', [Contabilidad::class, 'procesarCartola']); $app->post('/procesar[/]', [Contabilidad::class, 'procesarCartola']);
}); });
$app->group('/cartola', function($app) { $app->group('/cartola', function($app) {
$app->group('/diaria', function($app) {
$app->post('/procesar[/]', [Contabilidad::class, 'procesarCartolaDiaria']);
});
$app->post('/exportar[/]', [Contabilidad::class, 'exportarCartola']); $app->post('/exportar[/]', [Contabilidad::class, 'exportarCartola']);
}); });

View File

@ -39,6 +39,16 @@ return [
->register('itau', $container->get(Incoviba\Service\Cartola\Itau::class)) ->register('itau', $container->get(Incoviba\Service\Cartola\Itau::class))
->register('santander', $container->get(Incoviba\Service\Cartola\Santander::class)); ->register('santander', $container->get(Incoviba\Service\Cartola\Santander::class));
}, },
Incoviba\Service\Cartola\Diaria::class => function(ContainerInterface $container) {
return (new Incoviba\Service\Cartola\Diaria(
$container->get(Incoviba\Repository\Inmobiliaria\Cuenta::class),
$container->get(Incoviba\Repository\Movimiento::class),
$container->get(Incoviba\Repository\Cartola::class)
))
->register('security', $container->get(Incoviba\Service\Cartola\Security::class))
->register('itau', $container->get(Incoviba\Service\Cartola\Itau::class))
->register('santander', $container->get(Incoviba\Service\Cartola\Santander::class));
},
Incoviba\Common\Define\Contabilidad\Exporter::class => function(ContainerInterface $container) { Incoviba\Common\Define\Contabilidad\Exporter::class => function(ContainerInterface $container) {
return $container->get(Incoviba\Service\Contabilidad\Exporter\Nubox::class); return $container->get(Incoviba\Service\Contabilidad\Exporter\Nubox::class);
}, },

View File

@ -2,13 +2,14 @@
namespace Incoviba\Controller\API; namespace Incoviba\Controller\API;
use DateTimeImmutable; use DateTimeImmutable;
use Incoviba\Common\Ideal\Controller;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Incoviba\Common\Implement\Exception\EmptyResult; use Incoviba\Common\Implement\Exception\EmptyResult;
use Incoviba\Repository; use Incoviba\Repository;
use Incoviba\Service; use Incoviba\Service;
class Contabilidad class Contabilidad extends Controller
{ {
use withJson; use withJson;
@ -49,4 +50,25 @@ class Contabilidad
} catch (EmptyResult) {} } catch (EmptyResult) {}
return $this->withJson($response, $output); return $this->withJson($response, $output);
} }
public function procesarCartolaDiaria(ServerRequestInterface $request, ResponseInterface $response,
Repository\Inmobiliaria $inmobiliariaRepository,
Repository\Banco $bancoRepository,
Service\Cartola\Diaria $cartolaService): ResponseInterface
{
$body = $request->getParsedBody();
$output = [
'input' => $body,
'cartola' => []
];
try {
$inmobiliaria = $inmobiliariaRepository->fetchById($body['inmobiliaria_rut']);
$banco = $bancoRepository->fetchById($body['banco_id']);
$fecha = new DateTimeImmutable($body['fecha']);
$file = $request->getUploadedFiles()['file'];
$output['cartola'] = $cartolaService->process($inmobiliaria, $banco, $fecha, $file);
} catch (EmptyResult $exception) {
$this->logger->debug($exception);
}
return $this->withJson($response, $output);
}
} }

26
app/src/Model/Cartola.php Normal file
View File

@ -0,0 +1,26 @@
<?php
namespace Incoviba\Model;
use DateTimeInterface;
use Incoviba\Common\Ideal;
class Cartola extends Ideal\Model
{
public Inmobiliaria\Cuenta $cuenta;
public DateTimeInterface $fecha;
public int $cargos = 0;
public int $abonos = 0;
public int $saldo = 0;
public function jsonSerialize(): mixed
{
return array_merge(parent::jsonSerialize(), [
'cuenta_id' => $this->cuenta->id,
'fecha' => $this->fecha->format('Y-m-d'),
'cargos' => $this->cargos,
'abonos' => $this->abonos,
'saldo' => $this->saldo
]);
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace Incoviba\Model;
use DateTimeInterface;
use Incoviba\Common\Ideal;
class Movimiento extends Ideal\Model
{
public Inmobiliaria\Cuenta $cuenta;
public DateTimeInterface $fecha;
public string $glosa;
public string $documento;
public int $cargo;
public int $abono;
public int $saldo;
public function jsonSerialize(): mixed
{
return array_merge(parent::jsonSerialize(), [
'cuenta_id' => $this->cuenta->id,
'fecha' => $this->fecha->format('Y-m-d'),
'glosa' => $this->glosa,
'documento' => $this->documento,
'cargo' => $this->cargo,
'abono' => $this->abono,
'saldo' => $this->saldo
]);
}
}

View File

@ -0,0 +1,60 @@
<?php
namespace Incoviba\Repository;
use DateTimeInterface;
use Incoviba\Common\Define;
use Incoviba\Common\Ideal;
use Incoviba\Common\Implement;
use Incoviba\Model;
use Incoviba\Repository;
class Cartola extends Ideal\Repository
{
public function __construct(Define\Connection $connection, protected Repository\Inmobiliaria\Cuenta $cuentaRepository)
{
parent::__construct($connection);
$this->setTable('cartolas');
}
public function create(?array $data = null): Model\Cartola
{
$map = (new Implement\Repository\MapperParser(['cargos', 'abonos', 'saldo']))
->register('fecha', new Implement\Repository\Mapper\DateTime('fecha'))
->register('cuenta_id', (new Implement\Repository\Mapper())
->setProperty('cuenta')
->setFunction(function($data) {
return $this->cuentaRepository->fetchById($data['cuenta_id']);
}));
return $this->parseData(new Model\Cartola(), $data, $map);
}
public function save(Define\Model $model): Model\Cartola
{
$model->id = $this->saveNew([
'cuenta_id',
'fecha',
'cargos',
'abonos',
'saldo'
], [
$model->cuenta->id,
$model->fecha->format('Y-m-d'),
$model->cargos,
$model->abonos,
$model->saldo
]);
return $model;
}
public function edit(Define\Model $model, array $new_data): Model\Cartola
{
return $this->update($model, ['cuenta_id', 'fecha', 'cargos', 'abonos', 'saldo'], $new_data);
}
public function fetchByCuentaAndFecha(int $cuenta_id, DateTimeInterface $fecha): Model\Cartola
{
$query = $this->connection->getQueryBuilder()
->select()
->from($this->getTable())
->where('cuenta_id = ? AND fecha = ?');
return $this->fetchOne($query, [$cuenta_id, $fecha->format('Y-m-d')]);
}
}

View File

@ -6,6 +6,7 @@ use Incoviba\Common\Ideal;
use Incoviba\Repository; use Incoviba\Repository;
use Incoviba\Model; use Incoviba\Model;
use Incoviba\Common\Implement; use Incoviba\Common\Implement;
use PhpParser\Node\Expr\BinaryOp\Mod;
class Cuenta extends Ideal\Repository class Cuenta extends Ideal\Repository
{ {
@ -49,4 +50,12 @@ class Cuenta extends Ideal\Repository
->where('inmobiliaria = ?'); ->where('inmobiliaria = ?');
return $this->fetchMany($query, [$inmobiliaria_rut]); return $this->fetchMany($query, [$inmobiliaria_rut]);
} }
public function fetchByInmobiliariaAndBanco(int $inmobiliaria_rut, int $banco_id): Model\Inmobiliaria\Cuenta
{
$query = $this->connection->getQueryBuilder()
->select()
->from($this->getTable())
->where('inmobiliaria = ? AND banco = ?');
return $this->fetchOne($query, [$inmobiliaria_rut, $banco_id]);
}
} }

View File

@ -0,0 +1,64 @@
<?php
namespace Incoviba\Repository;
use DateTimeInterface;
use Incoviba\Common\Define;
use Incoviba\Common\Ideal;
use Incoviba\Common\Implement;
use Incoviba\Model;
class Movimiento extends Ideal\Repository
{
public function __construct(Define\Connection $connection, protected Inmobiliaria\Cuenta $cuentaRepository)
{
parent::__construct($connection);
$this->setTable('movimientos');
}
public function create(?array $data = null): Model\Movimiento
{
$map = (new Implement\Repository\MapperParser(['cargo', 'abono', 'saldo', 'glosa', 'documento']))
->register('fecha', new Implement\Repository\Mapper\DateTime('fecha'))
->register('cuenta_id', (new Implement\Repository\Mapper())
->setProperty('cuenta')
->setFunction(function($data) {
return $this->cuentaRepository->fetchById($data['cuenta_id']);
})
);
return $this->parseData(new Model\Movimiento(), $data, $map);
}
public function save(Define\Model $model): Model\Movimiento
{
$model->id = $this->saveNew([
'cuenta_id',
'fecha',
'glosa',
'documento',
'cargo',
'abono',
'saldo'
], [
$model->cuenta->id,
$model->fecha->format('Y-m-d'),
$model->glosa,
$model->documento,
$model->cargo,
$model->abono,
$model->saldo
]);
return $model;
}
public function edit(Define\Model $model, array $new_data): Model\Movimiento
{
return $this->update($model, ['cuenta_id', 'fecha', 'glosa', 'documento', 'cargo', 'abono', 'saldo'], $new_data);
}
public function fetchByCuentaAndFechaAndMonto(int $cuenta_id, DateTimeInterface $fecha, int $monto): Model\Movimiento
{
$query = $this->connection->getQueryBuilder()
->select()
->from($this->getTable())
->where('cuenta_id = ? AND fecha = ? AND (cargo = ? OR abono = ?)');
return $this->fetchOne($query, [$cuenta_id, $fecha->format('Y-m-d'), $monto, $monto]);
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace Incoviba\Service\Cartola;
use DateTimeInterface;
use DateTimeImmutable;
use Psr\Http\Message\UploadedFileInterface;
use Incoviba\Common\Implement\Exception\EmptyResult;
use Incoviba\Common\Define;
use Incoviba\Model;
use Incoviba\Repository;
class Diaria
{
public function __construct(protected Repository\Inmobiliaria\Cuenta $cuentaRepository,
protected Repository\Movimiento $movimientoRepository,
protected Repository\Cartola $cartolaRepository) {}
protected array $bancos;
public function register(string $name, Define\Cartola\Banco $banco): Diaria
{
$this->bancos[$name] = $banco;
return $this;
}
public function process(Model\Inmobiliaria $inmobiliaria, Model\Banco $banco, DateTimeInterface $fecha, UploadedFileInterface $file): array
{
$cuenta = $this->cuentaRepository->fetchByInmobiliariaAndBanco($inmobiliaria->rut, $banco->id);
$ms = $this->bancos[strtolower($banco->nombre)]->process($file);
$ms = array_reverse($ms);
$c = array_shift($ms);
$cargos = 0;
$abonos = 0;
$saldo = $c['saldo'];
$movimientos = [];
foreach ($ms as $m) {
$m['cuenta_id'] = $cuenta->id;
try {
$movimiento = $this->movimientoRepository->fetchByCuentaAndFechaAndMonto($cuenta->id, new DateTimeImmutable($m['fecha']), $m['cargo'] ?? $m['abono']);
} catch (EmptyResult) {
$movimiento = $this->movimientoRepository->create($m);
$movimiento = $this->movimientoRepository->save($movimiento);
}
$movimientos []= $movimiento;
if ($movimiento->fecha === $fecha) {
$cargos += $movimiento->cargo;
$abonos += $movimiento->abono;
}
$saldo = $m['saldo'];
}
try {
$cartola = $this->cartolaRepository->fetchByCuentaAndFecha($cuenta->id, $fecha);
} catch (EmptyResult) {
$cartola = $this->cartolaRepository->create([
'cuenta_id' => $cuenta->id,
'fecha' => $fecha->format('Y-m-d'),
'cargos' => $cargos,
'abonos' => $abonos,
'saldo' => $saldo
]);
$cartola = $this->cartolaRepository->save($cartola);
}
return compact('cartola', 'movimientos');
}
}

View File

@ -24,8 +24,10 @@ class Security extends Banco
'fecha' => 'fecha', 'fecha' => 'fecha',
'descripción' => 'glosa', 'descripción' => 'glosa',
'número de documentos' => 'documento', 'número de documentos' => 'documento',
'nº documento' => 'documento',
'cargos' => 'cargo', 'cargos' => 'cargo',
'abonos' => 'abono' 'abonos' => 'abono',
'saldos' => 'saldo'
]; ];
} }
@ -33,10 +35,9 @@ class Security extends Banco
{ {
$filename = '/tmp/cartola.xls'; $filename = '/tmp/cartola.xls';
$file->moveTo($filename); $file->moveTo($filename);
$reader = PhpSpreadsheet\IOFactory::createReader('Xls'); $xlsx = @PhpSpreadsheet\IOFactory::load($filename);
$xlsx = $reader->load($filename);
$worksheet = $xlsx->getActiveSheet(); $worksheet = $xlsx->getActiveSheet();
$rows = $worksheet->getRowIterator(); $rows = $worksheet->getRowIterator(3);
$dataFound = false; $dataFound = false;
$columns = []; $columns = [];
$data = []; $data = [];
@ -44,10 +45,10 @@ class Security extends Banco
$cells = $row->getCellIterator(); $cells = $row->getCellIterator();
$rowData = []; $rowData = [];
foreach ($cells as $cell) { foreach ($cells as $cell) {
if ($cell->getColumn() === 'A' and $cell->getCalculatedValue() === "fecha ") { if ($cell->getColumn() === 'A' and $cell->getCalculatedValue() !== null and strtolower($cell->getCalculatedValue()) === "fecha ") {
$cols = $row->getColumnIterator(); $cols = $row->getColumnIterator();
foreach ($cols as $col) { foreach ($cols as $col) {
$columns[$col->getColumn()] = trim($col->getCalculatedValue()); $columns[$col->getColumn()] = trim(strtolower($col->getCalculatedValue()), '  ');
} }
$dataFound = true; $dataFound = true;
break; break;
@ -62,7 +63,11 @@ class Security extends Banco
$col = $columns[$cell->getColumn()]; $col = $columns[$cell->getColumn()];
$value = $cell->getCalculatedValue(); $value = $cell->getCalculatedValue();
if ($col === 'fecha') { if ($col === 'fecha') {
$value = PhpSpreadsheet\Shared\Date::excelToDateTimeObject($cell->getValue(), 'America/Santiago')->format('Y-m-d'); if ((int) $cell->getValue() !== $cell->getValue()) {
$value = implode('-', array_reverse(explode('-', $cell->getValue())));
} else {
$value = PhpSpreadsheet\Shared\Date::excelToDateTimeObject($cell->getValue(), 'America/Santiago')->format('Y-m-d');
}
} }
$rowData[$col] = $value; $rowData[$col] = $value;
} }