diff --git a/Dockerfile b/Dockerfile index c8dd985..4641cd6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,6 +10,7 @@ RUN pecl install xdebug-3.1.3 \ COPY ./php-errors.ini /usr/local/etc/php/conf.d/docker-php-errors.ini COPY ./php-xdebug.ini /usr/local/etc/php/conf.d/docker-php-xdebug.ini +COPY ./php-memory.ini /usr/local/etc/php/conf.d/docker-php-memory.ini COPY --from=composer /usr/bin/composer /usr/bin/composer diff --git a/api.compose.yml b/api.compose.yml new file mode 100644 index 0000000..e6cd59b --- /dev/null +++ b/api.compose.yml @@ -0,0 +1,9 @@ +services: + httpclient: + profiles: + - testing + container_name: incoviba_client + image: flawiddsouza/restfox + restart: unless-stopped + ports: + - "${HTTPCLIENT_PORT:-4004}:4004" diff --git a/app/common/Ideal/Repository.php b/app/common/Ideal/Repository.php index 527c6ae..af67721 100644 --- a/app/common/Ideal/Repository.php +++ b/app/common/Ideal/Repository.php @@ -37,6 +37,9 @@ abstract class Repository implements Define\Repository $this->connection->execute($query, [$model->id]); } + /** + * @throws EmptyResult + */ public function fetchById(int $id): Define\Model { $query = $this->connection->getQueryBuilder() @@ -45,6 +48,10 @@ abstract class Repository implements Define\Repository ->where("{$this->getKey()} = ?"); return $this->fetchOne($query, [$id]); } + + /** + * @throws EmptyResult + */ public function fetchAll(null|string|array $ordering = null): array { $query = $this->connection->getQueryBuilder() diff --git a/app/common/Implement/Exception/HttpResponse.php b/app/common/Implement/Exception/HttpResponse.php index 249c7d8..542984a 100644 --- a/app/common/Implement/Exception/HttpResponse.php +++ b/app/common/Implement/Exception/HttpResponse.php @@ -2,12 +2,18 @@ namespace Incoviba\Common\Implement\Exception; use Throwable; -use HttpResponseException; +use Exception; -class HttpResponse extends HttpResponseException +class HttpResponse extends Exception { - public function __construct($message = "", $code = 0, Throwable $previous = null) + public function __construct($reason = "", $message = "", $code = 0, Throwable $previous = null) { + $this->reason = "HTTP Reason: {$reason}"; parent::__construct($message, $code, $previous); } + protected string $reason; + public function getReason(): string + { + return $this->reason; + } } diff --git a/app/common/Implement/Repository/Mapper.php b/app/common/Implement/Repository/Mapper.php index a8dc82b..d17aeaf 100644 --- a/app/common/Implement/Repository/Mapper.php +++ b/app/common/Implement/Repository/Mapper.php @@ -4,6 +4,7 @@ namespace Incoviba\Common\Implement\Repository; use Error; use Closure; use Incoviba\Common\Define; +use Incoviba\Common\Implement\Exception\EmptyResult; class Mapper implements Define\Repository\Mapper { @@ -68,7 +69,15 @@ class Mapper implements Define\Repository\Mapper $value = $data[$column]; if ($this->hasFunction()) { if ($value !== null) { - $value = ($this->function)($data); + try { + $value = ($this->function)($data); + } catch (EmptyResult $exception) { + if ($this->hasDefault()) { + $value = $this->default; + } else { + throw $exception; + } + } } elseif ($this->hasDefault()) { $value = $this->default; } diff --git a/app/resources/routes/02_inmobiliarias.php b/app/resources/routes/02_inmobiliarias.php index 8991df7..ed79667 100644 --- a/app/resources/routes/02_inmobiliarias.php +++ b/app/resources/routes/02_inmobiliarias.php @@ -2,5 +2,15 @@ use Incoviba\Controller\Inmobiliarias; $app->group('/inmobiliarias', function($app) { + $folder = implode(DIRECTORY_SEPARATOR, [__DIR__, 'inmobiliarias']); + if (file_exists($folder)) { + $files = new FilesystemIterator($folder); + foreach ($files as $file) { + if ($file->isDir()) { + continue; + } + include_once $file->getRealPath(); + } + } $app->get('[/]', Inmobiliarias::class); })->add($app->getContainer()->get(Incoviba\Middleware\Authentication::class)); diff --git a/app/resources/routes/api/contabilidad/cartolas.php b/app/resources/routes/api/contabilidad/cartolas.php index 52cdf3c..9bc2f80 100644 --- a/app/resources/routes/api/contabilidad/cartolas.php +++ b/app/resources/routes/api/contabilidad/cartolas.php @@ -3,6 +3,7 @@ use Incoviba\Controller\API\Contabilidad\Cartolas; $app->group('/cartolas', function($app) { $app->post('/procesar[/]', [Cartolas::class, 'procesar']); + $app->post('/importar[/]', [Cartolas::class, 'importar']); }); $app->group('/cartola', function($app) { $app->group('/diaria', function($app) { diff --git a/app/resources/routes/api/contabilidad/nubox.php b/app/resources/routes/api/contabilidad/nubox.php index 98a2836..b367ae8 100644 --- a/app/resources/routes/api/contabilidad/nubox.php +++ b/app/resources/routes/api/contabilidad/nubox.php @@ -1,5 +1,4 @@ group('/nubox/{inmobiliaria_rut}', function($app) { @@ -10,5 +9,6 @@ $app->group('/nubox/{inmobiliaria_rut}', function($app) { $app->post('/mayor[/]', [Nubox::class, 'libroMayor']); $app->post('/diario[/]', [Nubox::class, 'libroDiario']); }); + $app->get('/facturas/{dia}[/]', [Nubox::class, 'facturas']); $app->post('/cuenta', [Nubox::class, 'cuenta']); }); diff --git a/app/resources/routes/api/contabilidad/tesoreria.php b/app/resources/routes/api/contabilidad/tesoreria.php new file mode 100644 index 0000000..238e85d --- /dev/null +++ b/app/resources/routes/api/contabilidad/tesoreria.php @@ -0,0 +1,6 @@ +group('/tesoreria', function($app) { + $app->post('/import[/]', [Tesoreria::class, 'import']); +}); diff --git a/app/resources/routes/api/inmobiliarias.php b/app/resources/routes/api/inmobiliarias.php index e751cbb..ae2e1de 100644 --- a/app/resources/routes/api/inmobiliarias.php +++ b/app/resources/routes/api/inmobiliarias.php @@ -15,7 +15,7 @@ $app->group('/inmobiliarias', function($app) { $app->get('[/]', Inmobiliarias::class); }); $app->group('/inmobiliaria/{inmobiliaria_rut}', function($app) { - $app->post('/agentes', [Inmobiliarias::class, 'agentes']); + $app->post('/proveedores', [Inmobiliarias::class, 'proveedores']); $app->get('/cuentas[/]', [Inmobiliarias::class, 'cuentas']); $app->get('/proyectos[/]', [Inmobiliarias::class, 'proyectos']); }); diff --git a/app/resources/routes/api/inmobiliarias/proveedores.php b/app/resources/routes/api/inmobiliarias/proveedores.php index 9e4efef..df5ab4b 100644 --- a/app/resources/routes/api/inmobiliarias/proveedores.php +++ b/app/resources/routes/api/inmobiliarias/proveedores.php @@ -1,11 +1,11 @@ group('/agentes', function($app) { +$app->group('/proveedores', function($app) { $app->post('/add[/]', [Agentes::class, 'add']); $app->post('/register[/]', [Agentes::class, 'register']); $app->get('[/]', Agentes::class); }); -$app->group('/agente/{agente_id}', function($app) { +$app->group('/proveedor/{agente_id}', function($app) { $app->post('/edit[/]', [Agentes::class, 'edit']); }); diff --git a/app/resources/routes/api/inmobiliarias/sociedades.php b/app/resources/routes/api/inmobiliarias/sociedades.php new file mode 100644 index 0000000..5ce542d --- /dev/null +++ b/app/resources/routes/api/inmobiliarias/sociedades.php @@ -0,0 +1,7 @@ +group('/sociedades', function($app) { + $app->post('/add[/]', [Sociedades::class, 'add']); + $app->get('[/]', Sociedades::class); +}); diff --git a/app/resources/routes/api/sociedades.php b/app/resources/routes/api/sociedades.php new file mode 100644 index 0000000..7d51925 --- /dev/null +++ b/app/resources/routes/api/sociedades.php @@ -0,0 +1,17 @@ +group('/sociedades', function($app) { + $app->group('/add', function($app) { + $app->post('/one[/]', Sociedades::class . ':add'); + $app->post('[/]', Sociedades::class . ':addMany'); + }); + $app->post('/get[/]', [Sociedades::class, 'getMany']); + $app->post('/edit[/]', [Sociedades::class, 'edit']); + $app->post('/delete[/]', [Sociedades::class, 'delete']); + $app->post('/asisgnar[/]', [Sociedades::class, 'asignar']); + $app->get('[/]', Sociedades::class); +}); +$app->group('/sociedad/{sociedad_rut}', function($app) { + $app->get('[/]', Sociedades::class . ':get'); +}); diff --git a/app/resources/routes/api/ventas/facturas.php b/app/resources/routes/api/ventas/facturas.php new file mode 100644 index 0000000..697f1b0 --- /dev/null +++ b/app/resources/routes/api/ventas/facturas.php @@ -0,0 +1,6 @@ +group('/facturas', function($app) { + $app->post('/add[/]', [Facturas::class, 'add']); +}); diff --git a/app/resources/routes/contabilidad/cartolas.php b/app/resources/routes/contabilidad/cartolas.php index 7bd0058..fe7a14e 100644 --- a/app/resources/routes/contabilidad/cartolas.php +++ b/app/resources/routes/contabilidad/cartolas.php @@ -3,4 +3,5 @@ use Incoviba\Controller\Contabilidad; $app->group('/cartolas', function($app) { $app->get('/diaria[/]', [Contabilidad::class, 'diaria']); + $app->get('/importar[/]', [Contabilidad::class, 'importar']); }); diff --git a/app/resources/routes/contabilidad/cuadratura.php b/app/resources/routes/contabilidad/cuadratura.php new file mode 100644 index 0000000..9572b80 --- /dev/null +++ b/app/resources/routes/contabilidad/cuadratura.php @@ -0,0 +1,4 @@ +get('/cuadratura[/]', [Contabilidad::class, 'cuadratura']); diff --git a/app/resources/routes/contabilidad/informes/tesoreria.php b/app/resources/routes/contabilidad/informes/tesoreria.php index 9cbca00..20c447e 100644 --- a/app/resources/routes/contabilidad/informes/tesoreria.php +++ b/app/resources/routes/contabilidad/informes/tesoreria.php @@ -1,6 +1,8 @@ group('/tesoreria', function($app) { + $app->get('/import[/]', [Tesoreria::class, 'import']); $app->get('[/[{fecha}[/]]]', [Contabilidad::class, 'tesoreria']); }); diff --git a/app/resources/routes/inmobiliarias/proveedores.php b/app/resources/routes/inmobiliarias/proveedores.php new file mode 100644 index 0000000..37c6a52 --- /dev/null +++ b/app/resources/routes/inmobiliarias/proveedores.php @@ -0,0 +1,6 @@ +group('/proveedores', function($app) { + $app->get('[/]', Proveedores::class); +}); diff --git a/app/resources/views/contabilidad/cartolas/diaria.blade.php b/app/resources/views/contabilidad/cartolas/diaria.blade.php index 316246b..2988a76 100644 --- a/app/resources/views/contabilidad/cartolas/diaria.blade.php +++ b/app/resources/views/contabilidad/cartolas/diaria.blade.php @@ -52,8 +52,7 @@ Cargo Abono Saldo - Centro de Costo - Detalle + Orden @@ -115,10 +114,85 @@ + @endsection @include('layout.head.styles.datatables') @include('layout.body.scripts.datatables') +@include('layout.body.scripts.rut') @push('page_scripts') +@endpush diff --git a/app/resources/views/contabilidad/cuadratura.blade.php b/app/resources/views/contabilidad/cuadratura.blade.php new file mode 100644 index 0000000..e833686 --- /dev/null +++ b/app/resources/views/contabilidad/cuadratura.blade.php @@ -0,0 +1,225 @@ +@extends('layout.base') + +@section('page_content') +
+

+ Cuadratura de Cartola Mensual +

+
+
+
+
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+
+
+ + + +
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+@endsection + +@include('layout.head.styles.datatables') +@include('layout.body.scripts.datatables') + +@push('page_scripts') + +@endpush diff --git a/app/resources/views/contabilidad/movimientos.blade.php b/app/resources/views/contabilidad/movimientos.blade.php index 5e7713c..9ff85f1 100644 --- a/app/resources/views/contabilidad/movimientos.blade.php +++ b/app/resources/views/contabilidad/movimientos.blade.php @@ -71,7 +71,7 @@ - ' ].join("\n") @@ -868,7 +949,7 @@ 'SUBTOTAL (Bruto): $' + formatters.pesos.format((venta.neto + venta.iva) * propietario.props.proporcion) + '
' + 'Mas valor terreno: $' + ((venta.exento > 0) ? formatters.pesos.format(venta.exento * propietario.props.proporcion) : emptyTerreno) + '
' + 'TOTAL (Escritura): $' + formatters.pesos.format(venta.total * propietario.props.proporcion) + '; ' + formatters.ufs.format(venta.totalUF * propietario.props.proporcion) + ' UF

' + - 'Descuento Terreno: ' + ((venta.exento > 0) ? formatters.percent.format(venta.descuento * 100) : emptyTerreno) + '%

' + + 'Descuento Terreno: ' + ((venta.exento > 0) ? formatters.percent.format(venta.descuento * propietario.props.proporcion * 100) : emptyTerreno) + '%

' + 'UF (' + formatters.date.format(uf.fecha) + '): $' + formatters.ufs.format(uf.valor), '1 UNID', formatters.pesos.format(venta.exento * propietario.props.proporcion), @@ -920,6 +1001,28 @@ '', '' ].join("\n") + }, + guardar: ({index}) => { + if (this.props.saved) { + return [ + '
', + '
', + '
', + '
', + '', + 'Guardada', + '
', + '
', + '
' + ].join("\n") + } + return [ + '
', + '
', + ``, + '
', + '
' + ].join("\n") } } } @@ -942,6 +1045,10 @@ }, facturas: () => { document.getElementById(this.ids.facturas).innerHTML = this.venta.draw().facturas(this.formatters) + $('button.guardar').click(clickEvent => { + const index = clickEvent.currentTarget.getAttribute('data-index') + facturas.venta.save().factura({index: index-1}) + }) } } }, @@ -955,7 +1062,7 @@ rut: '{{$venta->proyecto()->inmobiliaria()->rut()}}', nombre: '{{$venta->proyecto()->inmobiliaria()->nombreCompleto()}}' }, - direccion: '{{$venta->proyecto()->direccion()->simple()}}' + direccion: '{{$venta->proyecto()->direccion()->simple()}}, {{$venta->proyecto()->direccion()->comuna->descripcion}}' }, valor: {{$venta->valor}}, uf: { @@ -990,15 +1097,35 @@ propietarios: [], facturas: [] }) - this.venta.add().propietario({ - rut: '{{$venta->propietario()->rut()}}', - nombre: '{{$venta->propietario()->nombreCompleto()}}', - proporcion: 1, - direccion: '{{$venta->propietario()->datos->direccion->simple()}}', - comuna: '{{$venta->propietario()->datos->direccion->comuna->descripcion}}', - fecha: new Date('{{$venta->currentEstado()->fecha->add(new DateInterval('P1D'))->format('Y-m-d')}}'), - uf: {{$uf}} - }) + @if (count($facturas) > 0) + this.venta.props.uf = { + fecha: new Date('{{$facturas[0]->fechaUF->format('Y-m-d')}}'), + valor: {{$facturas[0]->valorUF}} + } + @foreach ($facturas as $factura) + this.venta.props.facturas[{{$factura->index-1}}] = new Factura(JSON.parse('{!! json_encode($factura) !!}')) + this.venta.props.facturas[{{$factura->index-1}}].props.saved = true + this.venta.props.propietarios[{{$factura->index-1}}] = new Propietario({ + index: {{$factura->index}}, + proporcion: {{$factura->proporcion}}, + rut: '{{$factura->receptorRut}}', + nombre: '{{$factura->receptorNombre}}', + direccion: '{{$factura->receptorDireccion}}', + comuna: '{{$factura->receptorComuna}}', + fecha: new Date('{{$factura->fecha->format('Y-m-d')}}'), + }) + @endforeach + @else + this.venta.add().propietario({ + rut: '{{$venta->propietario()->rut()}}', + nombre: '{{$venta->propietario()->nombreCompleto()}}', + proporcion: 1, + direccion: '{{$venta->propietario()->datos->direccion->simple()}}', + comuna: '{{$venta->propietario()->datos->direccion->comuna->descripcion}}', + fecha: new Date('{{$venta->currentEstado()->fecha->add(new DateInterval('P1D'))->format('Y-m-d')}}'), + uf: {{$uf}} + }) + @endif this.draw().venta() this.draw().facturas() } diff --git a/app/setup/setups/services.php b/app/setup/setups/services.php index 2864326..0c14f39 100644 --- a/app/setup/setups/services.php +++ b/app/setup/setups/services.php @@ -72,8 +72,8 @@ return [ ) ->register('xlsx', Incoviba\Service\Informe\Excel::class); }, - Incoviba\Service\Contabilidad\Informe\Tesoreria\Excel::class => function(ContainerInterface $container) { - return new Incoviba\Service\Contabilidad\Informe\Tesoreria\Excel( + \Incoviba\Service\Contabilidad\Informe\Tesoreria\Output\Excel::class => function(ContainerInterface $container) { + return new \Incoviba\Service\Contabilidad\Informe\Tesoreria\Output\Excel( $container->get(Psr\Log\LoggerInterface::class), $container->get('folders')->get('informes'), $container->get(Incoviba\Service\UF::class), diff --git a/app/src/Controller/API/Contabilidad/Cartolas.php b/app/src/Controller/API/Contabilidad/Cartolas.php index 179c7e2..b8ad3e0 100644 --- a/app/src/Controller/API/Contabilidad/Cartolas.php +++ b/app/src/Controller/API/Contabilidad/Cartolas.php @@ -5,10 +5,14 @@ use DateTimeImmutable; use Incoviba\Common\Ideal\Controller; use Incoviba\Common\Implement\Exception\EmptyResult; use Incoviba\Controller\API\withJson; +use Incoviba\Model\Contabilidad\Banco; +use Incoviba\Model\Inmobiliaria; use Incoviba\Repository; use Incoviba\Service; +use PhpParser\Node\Stmt\TryCatch; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use Psr\Log\LoggerInterface; class Cartolas extends Controller { @@ -95,4 +99,60 @@ class Cartolas extends Controller } catch (EmptyResult) {} return $this->withJson($response, $output); } + public function importar(ServerRequestInterface $request, ResponseInterface $response, + LoggerInterface $logger, + Repository\Inmobiliaria $inmobiliariaRepository, + Repository\Contabilidad\Banco $bancoRepository, + Repository\Inmobiliaria\Cuenta $cuentaRepository, + Service\Contabilidad\Cartola $cartolaService, + Service\Contabilidad\Movimiento $movimientoService): ResponseInterface + { + $body = $request->getParsedBody(); + $files = $request->getUploadedFiles(); + + $output = [ + 'input' => $body, + 'movimientos' => [] + ]; + if (is_array($files['file'])) { + foreach ($files['file'] as $i => $file) { + if ($file->getError() !== UPLOAD_ERR_OK) { + continue; + } + try { + $inmobiliaria = $inmobiliariaRepository->fetchById($body['sociedad_rut'][$i]); + $banco = $bancoRepository->fetchById($body['banco_id'][$i]); + $movimientos = $cartolaService->process($inmobiliaria, $banco, new DateTimeImmutable($body['mes'][$i]), $file); + $cuenta = $cuentaRepository->fetchByInmobiliariaAndBanco($inmobiliaria->rut, $banco->id); + $this->addMovimientos($movimientoService, $cuenta, $movimientos); + $output['movimientos'] = array_merge($output['movimientos'], $movimientos); + } catch (EmptyResult) {} + } + } else { + try { + $inmobiliaria = $inmobiliariaRepository->fetchById($body['sociedad_rut']); + $banco = $bancoRepository->fetchById($body['banco_id']); + $movimientos = $cartolaService->process($inmobiliaria, $banco, new DateTimeImmutable($body['mes']), $files['file']); + $cuenta = $cuentaRepository->fetchByInmobiliariaAndBanco($inmobiliaria->rut, $banco->id); + $this->addMovimientos($movimientoService, $cuenta, $movimientos); + $output['movimientos'] = $movimientos; + } catch (EmptyResult) {} + } + return $this->withJson($response, $output); + } + + protected function addMovimientos(Service\Contabilidad\Movimiento $movimientoService, Inmobiliaria\Cuenta $cuenta, array $movimientos): void + { + foreach ($movimientos as $dataMovimiento) { + $dataMovimiento['cuenta_id'] = $cuenta->id; + $dataMovimiento['centro_costo_id'] = $dataMovimiento['centro_costo']; + $dataMovimiento['fecha'] = new DateTimeImmutable($dataMovimiento['fecha']); + if (array_key_exists('rut', $dataMovimiento)) { + list($rut, $digito) = explode('-', $dataMovimiento['rut']); + $dataMovimiento['rut'] = preg_replace('/\D+/', '', $rut); + $dataMovimiento['digito'] = $digito; + } + $movimientoService->add($dataMovimiento); + } + } } diff --git a/app/src/Controller/API/Contabilidad/Movimientos.php b/app/src/Controller/API/Contabilidad/Movimientos.php index 3daeb2d..c5030cb 100644 --- a/app/src/Controller/API/Contabilidad/Movimientos.php +++ b/app/src/Controller/API/Contabilidad/Movimientos.php @@ -23,29 +23,30 @@ class Movimientos extends Ideal\Controller 'movimiento_id' => $movimiento_id, 'input' => $body, 'status' => false, - 'movimiento' => null, - 'centro' => null, - 'detalle' => '' + 'movimiento' => null ]; try { $movimiento = $movimientoService->getById($movimiento_id); $output['movimiento'] = $this->movimientosToArray([$movimiento])[0]; $data = []; - if (isset($body['centro_id'])) { - $centro = $centroCostoRepository->fetchById($body['centro_id']); - $data['centro_costo_id'] = $centro->id; - } - if (isset($body['detalle'])) { - $data['detalle'] = $body['detalle']; + $fieldMap = [ + 'centro_costo_id', + 'categoria', + 'detalle', + 'rut', + 'digito', + 'nombres', + 'identificador' + ]; + foreach ($fieldMap as $field) { + if (key_exists($field, $body)) { + $data[$field] = $body[$field]; + } } + $movimientoService->setDetalles($movimiento, $data); $output['movimiento'] = $this->movimientosToArray([$movimientoService->getById($movimiento->id)])[0]; - if (isset($body['centro_id'])) { - $output['centro'] = $centro; - } - if (isset($body['detalle'])) { - $output['detalle'] = $body['detalle']; - } + $output['status'] = true; } catch (EmptyResult) {} return $this->withJson($response, $output); } diff --git a/app/src/Controller/API/Contabilidad/Nubox.php b/app/src/Controller/API/Contabilidad/Nubox.php index 2fce7b1..c554dea 100644 --- a/app/src/Controller/API/Contabilidad/Nubox.php +++ b/app/src/Controller/API/Contabilidad/Nubox.php @@ -120,4 +120,22 @@ class Nubox } return $this->withJson($response, $output); } + public function facturas(ServerRequestInterface $request, ResponseInterface $response, Service\Contabilidad\Nubox $nuboxService, int $inmobiliaria_rut, string $dia): ResponseInterface + { + $output = [ + 'inmobiliaria_rut' => $inmobiliaria_rut, + 'dia' => $dia, + 'facturas' => [] + ]; + try { + $output['facturas'] = $nuboxService->getFacturas($inmobiliaria_rut, new DateTimeImmutable($dia)); + } catch (HttpResponse $exception) { + $output['error'] = [ + 'code' => $exception->getCode(), + 'reason' => $exception->getReason(), + 'message' => $exception->getMessage(), + ]; + } + return $this->withJson($response, $output); + } } diff --git a/app/src/Controller/API/Contabilidad/Tesoreria.php b/app/src/Controller/API/Contabilidad/Tesoreria.php new file mode 100644 index 0000000..651cd2f --- /dev/null +++ b/app/src/Controller/API/Contabilidad/Tesoreria.php @@ -0,0 +1,29 @@ +getUploadedFiles(); + $output = []; + foreach ($files['file'] as $file) { + if ($file->getError() !== UPLOAD_ERR_OK) { + continue; + } + $data = $tesoreriaService->getInput()->loadFromExcel($file); + $tesoreriaService->getInput()->load($data); + $output['informes'] []= $data; + } + return $this->withJson($response, $output); + } +} diff --git a/app/src/Controller/API/Inmobiliarias.php b/app/src/Controller/API/Inmobiliarias.php index 98bdd84..4c50a76 100644 --- a/app/src/Controller/API/Inmobiliarias.php +++ b/app/src/Controller/API/Inmobiliarias.php @@ -55,27 +55,33 @@ class Inmobiliarias } catch (EmptyResult) {} return $this->withJson($response, $output); } - public function agentes(ServerRequestInterface $request, ResponseInterface $response, - Repository\Inmobiliaria $inmobiliariaRepository, - Repository\Inmobiliaria\SociedadAgente $sociedadAgenteRepository, - Repository\Inmobiliaria\TipoAgente $tipoAgenteRepository, - int $inmobiliaria_rut): ResponseInterface + public function proveedores(ServerRequestInterface $request, ResponseInterface $response, + Repository\Inmobiliaria $inmobiliariaRepository, + Repository\Inmobiliaria\SociedadAgente $sociedadAgenteRepository, + Repository\Inmobiliaria\TipoAgente $tipoAgenteRepository, + int $inmobiliaria_rut): ResponseInterface { $input = $request->getParsedBody(); $output = [ 'sociedad_rut' => $inmobiliaria_rut, 'input' => $input, 'sociedad' => null, - 'agentes' => [] + 'proveedores' => [] ]; try { $inmobiliaria = $inmobiliariaRepository->fetchById($inmobiliaria_rut); $output['sociedad'] = $inmobiliaria; if (isset($input['tipo_agente_id'])) { $tipo = $tipoAgenteRepository->fetchById($input['tipo_agente_id']); - $output['agentes'] = $sociedadAgenteRepository->fetchBySociedadAndTipo($inmobiliaria->rut, $tipo->id); + $proveedores = $sociedadAgenteRepository->fetchBySociedadAndTipo($inmobiliaria->rut, $tipo->id); } else { - $output['agentes'] = $sociedadAgenteRepository->fetchBySociedad($inmobiliaria->rut); + $proveedores = $sociedadAgenteRepository->fetchBySociedad($inmobiliaria->rut); + } + $output['proveedores'] = json_decode(json_encode($proveedores), JSON_OBJECT_AS_ARRAY); + foreach ($proveedores as $i => $proveedor) { + $output['proveedores'][$i]['sociedad'] = $proveedor->sociedad; + $output['proveedores'][$i]['proveedor'] = $proveedor->agenteTipo->agente; + $output['proveedores'][$i]['tipo'] = $proveedor->agenteTipo->tipoAgente; } } catch (EmptyResult) {} return $this->withJson($response, $output); diff --git a/app/src/Controller/API/Inmobiliarias/Sociedades.php b/app/src/Controller/API/Inmobiliarias/Sociedades.php new file mode 100644 index 0000000..8c4d693 --- /dev/null +++ b/app/src/Controller/API/Inmobiliarias/Sociedades.php @@ -0,0 +1,35 @@ +getParsedBody(); + $output = [ + 'input' => $input, + 'sociedad' => null + ]; + try { + $data = json_decode($input, true); + $contacto = $personaService->add($data['contacto']); + $data['contacto_rut'] = $contacto->rut; + unset($data['contacto']); + $output['sociedad'] = $sociedadService->add($data); + } catch (EmptyResult) { + $output['error'] = 'No se pudo agregar la sociedad'; + } + return $this->withJson($response, $output); + } +} diff --git a/app/src/Controller/API/Sociedades.php b/app/src/Controller/API/Sociedades.php new file mode 100644 index 0000000..50577f7 --- /dev/null +++ b/app/src/Controller/API/Sociedades.php @@ -0,0 +1,132 @@ + $sociedadService->getAll('nombre'), + ]; + return $this->withJson($response, $output); + } + public function getMany(ServerRequestInterface $request, ResponseInterface $response, Service\Sociedad $sociedadService): ResponseInterface + { + $input = $request->getParsedBody(); + $output = [ + 'input' => $input, + 'sociedades' => [], + ]; + foreach ($input['sociedades_ruts'] as $rut) { + $sociedad = $sociedadService->getByRut($rut); + if ($sociedad === null) { + continue; + } + $output['sociedades'][] = $sociedad; + } + return $this->withJson($response, $output); + } + public function get(ServerRequestInterface $request, ResponseInterface $response, Service\Sociedad $sociedadService, int $sociedad_rut): ResponseInterface + { + $output = [ + 'sociedad_rut' => $sociedad_rut, + 'sociedad' => $sociedadService->getByRut($sociedad_rut), + ]; + return $this->withJson($response, $output); + } + public function add(ServerRequestInterface $request, ResponseInterface $response, Service\Sociedad $sociedadService): ResponseInterface + { + $input = $request->getParsedBody(); + $output = [ + 'input' => $input, + 'sociedad' => $sociedadService->add($input), + ]; + return $this->withJson($response, $output); + } + public function addMany(ServerRequestInterface $request, ResponseInterface $response, Service\Sociedad $sociedadService, Service\Persona $personaService): ResponseInterface + { + $input = $request->getParsedBody(); + $output = [ + 'input' => $input, + 'sociedades' => [], + ]; + try { + if (json_decode($input) !== null) { + $input = json_decode($input, true); + } + } catch (\TypeError) {} + foreach ($input['sociedades'] as $sociedadData) { + try { + if (json_decode($sociedadData) !== null) { + $sociedadData = json_decode($sociedadData, true); + } + } catch (\TypeError) {} + $contacto = $personaService->add($sociedadData['contacto']); + $sociedadData['contacto_rut'] = $contacto->rut; + unset($sociedadData['contacto']); + $sociedad = $sociedadService->add($sociedadData); + if ($sociedad === null) { + continue; + } + $output['sociedades'][] = $sociedad; + } + return $this->withJson($response, $output); + } + public function edit(ServerRequestInterface $request, ResponseInterface $response, Service\Sociedad $sociedadService): ResponseInterface + { + $input = $request->getParsedBody(); + $output = [ + 'input' => $input, + 'sociedades' => [], + ]; + foreach ($input['sociedades'] as $sociedadData) { + $sociedad = $sociedadService->edit($sociedadData['rut'], $sociedadData); + if ($sociedad === null) { + continue; + } + $output['sociedades'][] = $sociedad; + } + return $this->withJson($response, $output); + } + public function delete(ServerRequestInterface $request, ResponseInterface $response, Service\Sociedad $sociedadService): ResponseInterface + { + $input = $request->getParsedBody(); + $output = [ + 'input' => $input, + 'sociedades' => [], + ]; + foreach ($input['sociedades_ruts'] as $rut) { + $sociedad = $sociedadService->getByRut($rut); + $deleted = $sociedadService->delete($rut); + $output['sociedades'][] = [ + 'sociedad' => $sociedad, + 'deleted' => $deleted, + ]; + } + return $this->withJson($response, $output); + } + + public function asignar(ServerRequestInterface $request, ResponseInterface $response, Service\Sociedad $sociedadService): ResponseInterface + { + $input = $request->getParsedBody(); + $output = [ + 'input' => $input, + 'proveedores' => [], + ]; + foreach ($input['proveedores'] as $proveedorData) { + $proveedor = $sociedadService->asignar($proveedorData['inmobiliaria_rut'], $proveedorData['sociedad_rut']); + if ($proveedor === null) { + continue; + } + $output['proveedores'][] = $proveedor; + } + return $this->withJson($response, $output); + } +} diff --git a/app/src/Controller/API/Ventas/Facturas.php b/app/src/Controller/API/Ventas/Facturas.php new file mode 100644 index 0000000..19c4ff2 --- /dev/null +++ b/app/src/Controller/API/Ventas/Facturas.php @@ -0,0 +1,32 @@ +getParsedBody(); + $output = [ + 'input' => $data, + 'factura' => null, + 'saved' => false + ]; + try { + $output['factura'] = $facturaService->add($data); + $output['saved'] = true; + } catch (Implement\Exception\EmptyResult) { + $output['error'] = 'No se pudo agregar la factura'; + return $this->withJson($response, $output, 400); + } + return $this->withJson($response, $output); + } +} diff --git a/app/src/Controller/Contabilidad.php b/app/src/Controller/Contabilidad.php index fc5aa54..9b4160c 100644 --- a/app/src/Controller/Contabilidad.php +++ b/app/src/Controller/Contabilidad.php @@ -34,6 +34,20 @@ class Contabilidad extends Controller $centrosCostos = $centroCostoRepository->fetchAll(); return $view->render($response, 'contabilidad.cartolas.diaria', compact('inmobiliarias', 'centrosCostos')); } + public function importar(ServerRequestInterface $request, ResponseInterface $response, View $view, + Repository\Inmobiliaria $inmobiliariaRepository, + Repository\Contabilidad\Banco $bancoRepository): ResponseInterface + { + $inmobiliarias = []; + try { + $inmobiliarias = $inmobiliariaRepository->fetchAll('razon'); + } catch (EmptyResult) {} + $bancos = []; + try { + $bancos = $bancoRepository->fetchAll('nombre'); + } catch (EmptyResult) {} + return $view->render($response, 'contabilidad.cartolas.import', compact('inmobiliarias', 'bancos')); + } public function depositos(ServerRequestInterface $request, ResponseInterface $response, View $view, Service\Redis $redisService, Repository\Inmobiliaria $inmobiliariaRepository, @@ -68,7 +82,7 @@ class Contabilidad extends Controller string $fecha = 'today'): ResponseInterface { $fecha = new DateTimeImmutable($fecha); - $anterior = $contabilidadService->getAnterior($fecha); + $anterior = $contabilidadService->getOutput()->getAnterior($fecha); $yesterday = new DateTimeImmutable('yesterday'); $siguiente = null; if ($yesterday > $fecha) { @@ -77,10 +91,16 @@ class Contabilidad extends Controller $siguiente = $fecha->add(new DateInterval('P3D')); } } - $informes = $contabilidadService->build($fecha); + $informes = $contabilidadService->getOutput()->build($fecha); $filename = "Informe de Tesorería {$fecha->format('d.m.Y')}"; return $view->render($response, 'contabilidad.informes.tesoreria', compact('fecha', 'anterior', 'siguiente', 'informes', 'filename')); } + /*public function semanal(ServerRequestInterface $request, ResponseInterface $response, View $view, + Service\Contabilidad\Informe\Semanal $semanalService, + string $fecha = 'today'): ResponseInterface + { + + }*/ public function cuadratura(ServerRequestInterface $request, ResponseInterface $response, View $view, Repository\Inmobiliaria $inmobiliariaRepository): ResponseInterface { diff --git a/app/src/Controller/Contabilidad/Informes.php b/app/src/Controller/Contabilidad/Informes.php index 6f3dc14..203dcf5 100644 --- a/app/src/Controller/Contabilidad/Informes.php +++ b/app/src/Controller/Contabilidad/Informes.php @@ -13,7 +13,7 @@ class Informes extends Ideal\Controller { $fecha = new DateTimeImmutable($fecha); - $tesoreriaService->buildInforme($fecha, $tesoreriaService->build($fecha)); + $tesoreriaService->getOutput()->buildInforme($fecha, $tesoreriaService->getOutput()->build($fecha)); $response->getBody()->write(file_get_contents('php://output')); return $response; } diff --git a/app/src/Controller/Contabilidad/Tesoreria.php b/app/src/Controller/Contabilidad/Tesoreria.php new file mode 100644 index 0000000..fe3924a --- /dev/null +++ b/app/src/Controller/Contabilidad/Tesoreria.php @@ -0,0 +1,14 @@ +render($response, 'contabilidad.tesoreria.import'); + } +} diff --git a/app/src/Controller/Inmobiliarias/Proveedores.php b/app/src/Controller/Inmobiliarias/Proveedores.php new file mode 100644 index 0000000..09d736e --- /dev/null +++ b/app/src/Controller/Inmobiliarias/Proveedores.php @@ -0,0 +1,27 @@ +getAll('nombre'); + } catch (EmptyResult) {} + $tiposSociedades = []; + try { + $tiposSociedades = $tipoSociedad->fetchAll('descripcion'); + } catch (EmptyResult) {} + return $view->render($response, 'inmobiliarias.proveedores', compact('sociedades', 'tiposSociedades')); + } +} diff --git a/app/src/Controller/Ventas/Facturacion.php b/app/src/Controller/Ventas/Facturacion.php index 0b5a689..868826c 100644 --- a/app/src/Controller/Ventas/Facturacion.php +++ b/app/src/Controller/Ventas/Facturacion.php @@ -26,9 +26,10 @@ class Facturacion extends Ideal\Controller * @throws Exception */ public function show(ServerRequestInterface $request, ResponseInterface $response, View $view, - Service\Venta $ventaService, Service\Proyecto\Terreno $terrenoService, - Service\IPC $ipcService, Service\UF $ufService, - int $venta_id): ResponseInterface + Service\Venta $ventaService, Service\Proyecto\Terreno $terrenoService, + Service\IPC $ipcService, Service\UF $ufService, + Service\Venta\Factura $facturasService, + int $venta_id): ResponseInterface { $venta = $ventaService->getById($venta_id); $uf = $ufService->get($venta->currentEstado()->fecha); @@ -48,7 +49,8 @@ class Facturacion extends Ideal\Controller $ipc = $ipcService->get($prevMonthTerreno, $prevMonth); } } + $facturas = $facturasService->getByVenta($venta->id); - return $view->render($response, 'ventas.facturacion.show', compact('venta', 'terreno', 'uf', 'ipc')); + return $view->render($response, 'ventas.facturacion.show', compact('venta', 'terreno', 'uf', 'ipc', 'facturas')); } } diff --git a/app/src/Model/Contabilidad/Movimiento.php b/app/src/Model/Contabilidad/Movimiento.php index 8bb0b91..1f4adbf 100644 --- a/app/src/Model/Contabilidad/Movimiento.php +++ b/app/src/Model/Contabilidad/Movimiento.php @@ -4,8 +4,8 @@ namespace Incoviba\Model\Contabilidad; use DateTimeInterface; use Incoviba\Common\Ideal; use Incoviba\Common\Implement\Exception\EmptyResult; +use Incoviba\Model\Contabilidad\Movimiento\Detalle; use Incoviba\Model\Inmobiliaria; -use Incoviba\Model\Movimiento\Detalle; class Movimiento extends Ideal\Model { @@ -21,15 +21,20 @@ class Movimiento extends Ideal\Model public function getDetalles(): ?Detalle { if (!isset($this->detalles)) { - try { - $this->detalles = $this->runFactory('detalles'); - } catch (EmptyResult) { - $this->detalles = null; - } + $this->detalles = $this->runFactory('detalles'); } return $this->detalles; } + /*protected ?array $auxiliares; + public function getAuxiliares(): ?array + { + if (!isset($this->auxiliares)) { + $this->auxiliares = $this->runFactory('auxiliares'); + } + return $this->auxiliares; + }*/ + public function jsonSerialize(): mixed { return array_merge(parent::jsonSerialize(), [ @@ -40,7 +45,8 @@ class Movimiento extends Ideal\Model 'cargo' => $this->cargo, 'abono' => $this->abono, 'saldo' => $this->saldo, - 'detalles' => $this->getDetalles() ?? null + 'detalles' => $this->getDetalles(), + //'auxiliares' => $this->getAuxiliares() ]); } } diff --git a/app/src/Model/Contabilidad/Movimiento/Auxiliar.php b/app/src/Model/Contabilidad/Movimiento/Auxiliar.php new file mode 100644 index 0000000..afbfe0a --- /dev/null +++ b/app/src/Model/Contabilidad/Movimiento/Auxiliar.php @@ -0,0 +1,36 @@ +detalles)) { + try { + $this->detalles = $this->runFactory('detalles'); + } catch (Implement\Exception\EmptyResult) { + $this->detalles = null; + } + } + return $this->detalles; + } + + public function jsonSerialize(): mixed + { + return array_merge(parent::jsonSerialize(), [ + 'movimiento_id' => $this->movimiento->id, + 'cargo' => $this->cargo, + 'abono' => $this->abono, + 'detalles' => $this->getDetalles() + ]); + } +} diff --git a/app/src/Model/Contabilidad/Movimiento/Auxiliar/Detalle.php b/app/src/Model/Contabilidad/Movimiento/Auxiliar/Detalle.php new file mode 100644 index 0000000..ea2e854 --- /dev/null +++ b/app/src/Model/Contabilidad/Movimiento/Auxiliar/Detalle.php @@ -0,0 +1,39 @@ +rut . '-' . $this->digito; + } + public function rutFormatted(): string + { + return number_format($this->rut, 0, ',', '.') . '-' . $this->digito; + } + + public function jsonSerialize(): mixed + { + return [ + 'auxiliar_id' => $this->auxiliar->id, + 'centro_costo' => $this->centroCosto, + 'rut' => $this->rut, + 'digito' => $this->digito, + 'nombre' => $this->nombre, + 'categoria' => $this->categoria, + 'detalle' => $this->detalle, + 'rutFormatted' => $this->rutFormatted(), + ]; + } +} diff --git a/app/src/Model/Contabilidad/Movimiento/Detalle.php b/app/src/Model/Contabilidad/Movimiento/Detalle.php new file mode 100644 index 0000000..8fabd68 --- /dev/null +++ b/app/src/Model/Contabilidad/Movimiento/Detalle.php @@ -0,0 +1,41 @@ +rut . '-' . $this->digito; + } + public function rutFormatted(): string + { + return number_format($this->rut, 0, ',', '.') . '-' . $this->digito; + } + + public function jsonSerialize(): mixed + { + return [ + 'movimiento_id' => $this->movimiento->id, + 'centro_costo' => $this->centroCosto, + 'rut' => $this->rut, + 'digito' => $this->digito, + 'nombres' => $this->nombres, + 'categoria' => $this->categoria, + 'detalle' => $this->detalle, + 'identificador' => $this->identificador, + 'rutFormatted' => $this->rutFormatted() + ]; + } +} diff --git a/app/src/Model/DatosPersona.php b/app/src/Model/DatosPersona.php new file mode 100644 index 0000000..c27f0d0 --- /dev/null +++ b/app/src/Model/DatosPersona.php @@ -0,0 +1,32 @@ + $this->direccion, + 'telefono' => $this->telefono, + 'email' => $this->email, + 'fechaNacimiento' => $this->fechaNacimiento, + 'sexo' => $this->sexo, + 'estadoCivil' => $this->estadoCivil, + 'nacionalidad' => $this->nacionalidad, + 'profesion' => $this->profesion, + ]; + } +} diff --git a/app/src/Model/Inmobiliaria/Proveedor.php b/app/src/Model/Inmobiliaria/Proveedor.php new file mode 100644 index 0000000..ccb8934 --- /dev/null +++ b/app/src/Model/Inmobiliaria/Proveedor.php @@ -0,0 +1,29 @@ +tipos)) { + $this->tipos = $this->runFactory('tipos'); + } + return $this->tipos; + } + + public function jsonSerialize(): mixed + { + return array_merge(parent::jsonSerialize(), [ + 'inmobiliaria' => $this->inmobiliaria, + 'sociedad' => $this->sociedad, + 'tipos' => $this->tipos(), + ]); + } +} diff --git a/app/src/Model/Movimiento/Detalle.php b/app/src/Model/Movimiento/Detalle.php deleted file mode 100644 index 96a75d5..0000000 --- a/app/src/Model/Movimiento/Detalle.php +++ /dev/null @@ -1,21 +0,0 @@ - $this->movimiento->id, - 'centro_costo' => $this->centroCosto, - 'detalle' => $this->detalle - ]; - } -} diff --git a/app/src/Model/Persona.php b/app/src/Model/Persona.php new file mode 100644 index 0000000..7e0c59a --- /dev/null +++ b/app/src/Model/Persona.php @@ -0,0 +1,46 @@ +nombres . ' ' . $this->apellidoPaterno . ' ' . $this->apellidoMaterno; + } + + public function rutCompleto(): string + { + return number_format($this->rut, 0, ',', '.') . '-' . $this->digito; + } + + protected ?DatosPersona $datos; + public function datos(): ?DatosPersona + { + if (!isset($this->datos)) { + $this->datos = $this->runFactory('datos'); + } + return $this->datos; + } + + public function jsonSerialize(): mixed + { + return [ + 'rut' => $this->rut, + 'digito' => $this->digito, + 'nombres' => $this->nombres, + 'apellidoPaterno' => $this->apellidoPaterno, + 'apellidoMaterno' => $this->apellidoMaterno, + 'nombreCompleto' => $this->nombreCompleto(), + 'rutCompleto' => $this->rutCompleto(), + 'datos' => $this->datos(), + ]; + } +} diff --git a/app/src/Model/Sociedad.php b/app/src/Model/Sociedad.php new file mode 100644 index 0000000..4e443cc --- /dev/null +++ b/app/src/Model/Sociedad.php @@ -0,0 +1,33 @@ +razonSocial, $this->tipoSociedad->descripcion]); + } + + public function jsonSerialize(): mixed + { + return [ + 'rut' => $this->rut, + 'digito' => $this->digito, + 'nombre' => $this->nombre, + 'razonSocial' => $this->razonSocial, + 'tipoSociedad' => $this->tipoSociedad, + 'contacto' => $this->contacto, + 'nombreCompleto' => $this->nombreCompleto(), + ]; + } +} diff --git a/app/src/Model/Venta/Factura.php b/app/src/Model/Venta/Factura.php new file mode 100644 index 0000000..cb0b259 --- /dev/null +++ b/app/src/Model/Venta/Factura.php @@ -0,0 +1,86 @@ +estados)) { + $this->estados = $this->runFactory('estados'); + } + return $this->estados ?? []; + } + + public function jsonSerialize(): mixed + { + return array_merge(parent::jsonSerialize(), [ + 'venta_id' => $this->venta->id, + 'index' => $this->index, + 'proporcion' => $this->proporcion, + 'emisor' => [ + 'rut' => $this->emisorRut, + 'nombre' => $this->emisorNombre, + 'direccion' => $this->emisorDireccion + ], + 'receptor' => [ + 'rut' => $this->receptorRut, + 'nombre' => $this->receptorNombre, + 'direccion' => $this->receptorDireccion, + 'comuna' => $this->receptorComuna + ], + 'fecha' => $this->fecha->format('Y-m-d'), + 'unidades' => $this->unidades, + 'detalle' => [ + 'base' => $this->detalleBase, + 'terreno' => $this->detalleTerreno, + 'neto' => $this->detalleNeto, + 'iva' => $this->detalleIva, + 'bruto' => $this->detalleBruto, + 'descuento' => $this->detalleDescuento, + 'total' => $this->detalleTotal + ], + 'total' => [ + 'neto' => $this->totalNeto, + 'exento' => $this->totalExento, + 'iva' => $this->totalIva, + 'total' => $this->totalTotal + ], + 'uf' => [ + 'fecha' => $this->fechaUF->format('Y-m-d'), + 'valor' => $this->valorUF + ], + 'estados' => $this->estados() + ]); + } +} diff --git a/app/src/Model/Venta/Factura/Estado.php b/app/src/Model/Venta/Factura/Estado.php new file mode 100644 index 0000000..3bae576 --- /dev/null +++ b/app/src/Model/Venta/Factura/Estado.php @@ -0,0 +1,22 @@ + $this->factura->id, + 'fecha' => $this->fecha->format('Y-m-d'), + 'tipo' => $this->tipo + ]); + } +} diff --git a/app/src/Model/Venta/Factura/Estado/Tipo.php b/app/src/Model/Venta/Factura/Estado/Tipo.php new file mode 100644 index 0000000..f53b978 --- /dev/null +++ b/app/src/Model/Venta/Factura/Estado/Tipo.php @@ -0,0 +1,7 @@ +update($model, ['nombre'], $new_data); } + + public function fetchByNombre(string $nombre): Model\Contabilidad\Banco + { + $query = $this->connection->getQueryBuilder() + ->select() + ->from($this->getTable()) + ->where('nombre = :nombre'); + return $this->fetchOne($query, ['nombre' => $nombre]); + } } diff --git a/app/src/Repository/Contabilidad/Movimiento.php b/app/src/Repository/Contabilidad/Movimiento.php index 4f36d3c..d45d8ca 100644 --- a/app/src/Repository/Contabilidad/Movimiento.php +++ b/app/src/Repository/Contabilidad/Movimiento.php @@ -62,13 +62,13 @@ class Movimiento extends Ideal\Repository ->where('cuenta_id = ? AND fecha = ?'); return $this->fetchMany($query, [$cuenta_id, $fecha->format('Y-m-d')]); } - public function fetchByCuentaAndFechaAndCargoAndAbonoAndSaldo(int $cuenta_id, DateTimeInterface $fecha, int $cargo, int $abono, int $saldo): Model\Contabilidad\Movimiento + public function fetchByCuentaAndFechaAndGlosaAndCargoAndAbonoAndSaldo(int $cuenta_id, DateTimeInterface $fecha, string $glosa, int $cargo, int $abono, int $saldo): Model\Contabilidad\Movimiento { $query = $this->connection->getQueryBuilder() ->select() ->from($this->getTable()) - ->where('cuenta_id = ? AND fecha = ? AND cargo = ? AND abono = ? AND saldo = ?'); - return $this->fetchOne($query, [$cuenta_id, $fecha->format('Y-m-d'), $cargo, $abono, $saldo]); + ->where('cuenta_id = ? AND fecha = ? AND glosa = ? AND cargo = ? AND abono = ? AND saldo = ?'); + return $this->fetchOne($query, [$cuenta_id, $fecha->format('Y-m-d'), $glosa, $cargo, $abono, $saldo]); } public function fetchAmountStartingFrom(int $start, int $amount): array { diff --git a/app/src/Repository/Contabilidad/Movimiento/Auxiliar.php b/app/src/Repository/Contabilidad/Movimiento/Auxiliar.php new file mode 100644 index 0000000..065a792 --- /dev/null +++ b/app/src/Repository/Contabilidad/Movimiento/Auxiliar.php @@ -0,0 +1,62 @@ +setTable('movimientos_auxiliares'); + } + + public function create(?array $data = null): Model\Contabilidad\Movimiento\Auxiliar + { + $map = (new Implement\Repository\MapperParser(['cargo', 'abono'])) + ->register('movimiento_id', (new Implement\Repository\Mapper()) + ->setProperty('movimiento') + ->setFunction(function($data) { + return $this->movimientoRepository->fetchById($data['movimiento_id']); + })); + return $this->parseData(new Model\Contabilidad\Movimiento\Auxiliar(), $data, $map); + } + public function save(Define\Model $model): Model\Contabilidad\Movimiento\Auxiliar + { + $model->id = $this->saveNew([ + 'movimiento_id', + 'cargo', + 'abono' + ],[ + $model->movimiento->id, + $model->cargo, + $model->abono + ]); + return $model; + } + public function edit(Define\Model $model, array $new_data): Model\Contabilidad\Movimiento\Auxiliar + { + return $this->update($model, [ + 'movimiento_id', + 'cargo', + 'abono' + ], $new_data); + } + + /** + * @throws EmptyResult + */ + public function fetchByMovimiento(int $movimiento_id): array + { + $query = $this->connection->getQueryBuilder() + ->select() + ->from($this->getTable()) + ->where('movimiento_id = :movimiento_id'); + return $this->fetchMany($query, ['movimiento_id' => $movimiento_id]); + } +} diff --git a/app/src/Repository/Contabilidad/Movimiento/Auxiliar/Detalle.php b/app/src/Repository/Contabilidad/Movimiento/Auxiliar/Detalle.php new file mode 100644 index 0000000..77c0b2e --- /dev/null +++ b/app/src/Repository/Contabilidad/Movimiento/Auxiliar/Detalle.php @@ -0,0 +1,72 @@ +setTable('auxiliar_detalles'); + } + + public function create(?array $data = null): Model\Contabilidad\Movimiento\Auxiliar\Detalle + { + $map = (new Implement\Repository\MapperParser(['rut', 'digito', 'nombre', 'categoria', 'detalle'])) + ->register('auxiliar_id', (new Implement\Repository\Mapper()) + ->setProperty('auxiliar') + ->setFunction(function($data) { + return $this->auxiliarRepository->fetchById($data['auxiliar_id']); + })) + ->register('centro_costo_id', (new Implement\Repository\Mapper()) + ->setProperty('centroCosto') + ->setFunction(function($data) { + return $this->centroCostoRepository->fetchById($data['centro_costo_id']); + }) + ->setDefault(null)); + return $this->parseData(new Model\Contabilidad\Movimiento\Auxiliar\Detalle(), $data, $map); + } + public function save(Define\Model $model): Model\Contabilidad\Movimiento\Auxiliar\Detalle + { + $this->saveNew([ + 'auxiliar_id', + 'rut', + 'digito', + 'nombre', + 'categoria', + 'detalle' + ], [ + $model->auxiliar->id, + $model->rut, + $model->digito, + $model->nombre, + $model->categoria, + $model->detalle + ]); + return $model; + } + public function edit(Define\Model $model, array $new_data): Model\Contabilidad\Movimiento\Auxiliar\Detalle + { + return $this->update($model, ['rut', 'digito', 'nombre', 'categoria', 'detalle'], $new_data); + } + + /** + * @throws EmptyResult + */ + public function fetchByAuxiliar(int $auxiliar_id): array + { + $query = $this->connection->getQueryBuilder() + ->select() + ->from($this->getTable()) + ->where('auxiliar_id = :auxiliar_id'); + return $this->fetchMany($query, ['auxiliar_id' => $auxiliar_id]); + } +} diff --git a/app/src/Repository/Movimiento/Detalle.php b/app/src/Repository/Contabilidad/Movimiento/Detalle.php similarity index 58% rename from app/src/Repository/Movimiento/Detalle.php rename to app/src/Repository/Contabilidad/Movimiento/Detalle.php index 349feda..ba526c2 100644 --- a/app/src/Repository/Movimiento/Detalle.php +++ b/app/src/Repository/Contabilidad/Movimiento/Detalle.php @@ -1,5 +1,5 @@ setTable('movimientos_detalles'); } - public function create(?array $data = null): Model\Movimiento\Detalle + public function create(?array $data = null): Model\Contabilidad\Movimiento\Detalle { - $map = (new Implement\Repository\MapperParser(['detalle'])) + $map = (new Implement\Repository\MapperParser(['rut', 'digito', 'nombres', 'categoria', 'detalle', 'identificador'])) ->register('movimiento_id', (new Implement\Repository\Mapper()) ->setProperty('movimiento') ->setFunction(function(array $data) { @@ -28,23 +29,24 @@ class Detalle extends Ideal\Repository ->setProperty('centroCosto') ->setFunction(function(array $data) { return $this->centroCostoRepository->fetchById($data['centro_costo_id']); - })); - return $this->parseData(new Model\Movimiento\Detalle(), $data, $map); + }) + ->setDefault(null)); + return $this->parseData(new Model\Contabilidad\Movimiento\Detalle(), $data, $map); } - public function save(Define\Model $model): Model\Movimiento\Detalle + public function save(Define\Model $model): Model\Contabilidad\Movimiento\Detalle { $this->saveNew( - ['movimiento_id', 'centro_costo_id', 'detalle'], - [$model->movimiento->id, $model->centroCosto->id, $model->detalle] + ['movimiento_id', 'centro_costo_id', 'rut', 'digito', 'nombres', 'categoria', 'detalle', 'identificador'], + [$model->movimiento->id, $model->centroCosto?->id, $model->rut, $model->digito, $model->nombres, $model->categoria, $model->detalle, $model->identificador] ); return $model; } - public function edit(Define\Model $model, array $new_data): Model\Movimiento\Detalle + public function edit(Define\Model $model, array $new_data): Model\Contabilidad\Movimiento\Detalle { - return $this->update($model, ['movimiento_id', 'centro_costo_id', 'detalle'], $new_data); + return $this->update($model, ['movimiento_id', 'centro_costo_id', 'rut', 'digito', 'nombres', 'categoria', 'detalle', 'identificador'], $new_data); } - public function fetchByMovimiento(int $movimiento_id): Model\Movimiento\Detalle + public function fetchByMovimiento(int $movimiento_id): Model\Contabilidad\Movimiento\Detalle { $query = $this->connection->getQueryBuilder() ->select() diff --git a/app/src/Repository/DatosPersona.php b/app/src/Repository/DatosPersona.php new file mode 100644 index 0000000..3b9c0c0 --- /dev/null +++ b/app/src/Repository/DatosPersona.php @@ -0,0 +1,86 @@ +setTable('datos_personas'); + } + + public function create(?array $data = null): Model\DatosPersona + { + $map = (new Implement\Repository\MapperParser()) + ->register('persona_rut', (new Implement\Repository\Mapper()) + ->setProperty('persona') + ->setFunction(function($data) { + return $this->personaRepository->fetchById($data['persona_rut']); + })) + ->register('direccion_id', (new Implement\Repository\Mapper()) + ->setProperty('direccion') + ->setFunction(function($data) { + return $this->direccionRepository->fetchById($data['direccion_id']); + })->setDefault(null)) + ->register('telefono', (new Implement\Repository\Mapper())->setFunction(function($data) { + return $data['telefono']; + })->setDefault(null)) + ->register('email', (new Implement\Repository\Mapper())->setFunction(function($data) { + return $data['email']; + })->setDefault(null)) + ->register('fecha_nacimiento', (new Implement\Repository\Mapper\DateTime('fecha_nacimiento')) + ->setDefault(null) + ->setProperty('fechaNacimiento')) + ->register('sexo', (new Implement\Repository\Mapper())->setFunction(function($data) { + return $data['sexo']; + })->setDefault(null)) + ->register('estado_civil', (new Implement\Repository\Mapper())->setFunction(function($data) { + return $data['estado_civil']; + })->setDefault(null)->setProperty('estadoCivil')) + ->register('nacionalidad', (new Implement\Repository\Mapper())->setFunction(function($data) { + return $data['nacionalidad']; + })->setDefault(null)) + ->register('profesion', (new Implement\Repository\Mapper())->setFunction(function($data) { + return $data['profesion']; + })->setDefault(null)); + return $this->parseData(new Model\DatosPersona(), $data, $map); + } + public function save(Define\Model $model): Model\DatosPersona + { + $this->saveNew([ + 'persona_rut', 'direccion_id', 'telefono', 'email', 'fecha_nacimiento', 'sexo', 'estado_civil', + 'nacionalidad', 'profesion' + ], [ + $model->persona->rut, $model->direccion?->id, $model->telefono, $model->email, $model->fechaNacimiento, + $model->sexo, $model->estadoCivil, $model->nacionalidad, $model->profesion + ]); + return $model; + } + public function edit(Define\Model $model, array $new_data): Model\DatosPersona + { + return $this->update($model, [ + 'direccion_id', 'telefono', 'email', 'fecha_nacimiento', 'sexo', 'estado_civil', + 'nacionalidad', 'profesion' + ], $new_data); + } + + public function fetchByPersona(int $persona_rut): Model\DatosPersona + { + $query = $this->connection->getQueryBuilder() + ->select() + ->from($this->getTable()) + ->where('persona_rut = ?'); + return $this->fetchOne($query, [$persona_rut]); + } + + protected function getKey(): string + { + return 'persona_rut'; + } +} diff --git a/app/src/Repository/Inmobiliaria/AgenteTipo.php b/app/src/Repository/Inmobiliaria/AgenteTipo.php index 0ec9ed6..d8d2a88 100644 --- a/app/src/Repository/Inmobiliaria/AgenteTipo.php +++ b/app/src/Repository/Inmobiliaria/AgenteTipo.php @@ -24,6 +24,7 @@ class AgenteTipo extends Ideal\Repository return ($data === null) ? null : $this->agenteRepository->fetchById($data['agente']); })) ->register('tipo', (new Implement\Repository\Mapper()) + ->setProperty('tipoAgente') ->setFunction(function(?array $data) { return ($data === null) ? null : $this->tipoAgenteRepository->fetchById($data['tipo']); })); diff --git a/app/src/Repository/Inmobiliaria/Proveedor.php b/app/src/Repository/Inmobiliaria/Proveedor.php new file mode 100644 index 0000000..2f9c27d --- /dev/null +++ b/app/src/Repository/Inmobiliaria/Proveedor.php @@ -0,0 +1,61 @@ +setTable('proveedores'); + } + + public function create(?array $data = null): Model\Inmobiliaria\Proveedor + { + $map = (new Implement\Repository\MapperParser()) + ->register('inmobiliaria_rut', (new Implement\Repository\Mapper()) + ->setProperty('inmobiliaria') + ->setFunction(function($data) { + return $this->inmobiliariaRepository->fetchById($data['inmobiliaria_rut']); + })) + ->register('sociedad_rut', (new Implement\Repository\Mapper()) + ->setProperty('sociedad') + ->setFunction(function($data) { + return $this->sociedadRepository->fetchById($data['sociedad_rut']); + })); + return $this->parseData(new Model\Inmobiliaria\Proveedor(), $data, $map); + } + public function save(Define\Model $model): Model\Inmobiliaria\Proveedor + { + $model->id = $this->saveNew(['inmobiliaria_rut', 'sociedad_rut'], [$model->inmobiliaria->rut, $model->sociedad->rut]); + return $model; + } + public function edit(Define\Model $model, array $new_data): Model\Inmobiliaria\Proveedor + { + return $this->update($model, ['sociedad_id'], $new_data); + } + + public function fetchByInmobiliaria(int $inmobiliaria_rut): array + { + $query = $this->connection->getQueryBuilder() + ->select() + ->from($this->getTable()) + ->where('inmobiliaria_rut = :inmobiliaria_rut'); + return array_map([$this, 'load'], $this->fetchMany($query, compact('inmobiliaria_rut'))); + } + public function fetchBySociedad(int $sociedad_rut): array + { + $query = $this->connection->getQueryBuilder() + ->select() + ->from($this->getTable()) + ->where('sociedad_rut = :sociedad_rut'); + return array_map([$this, 'load'], $this->fetchMany($query, compact('sociedad_rut'))); + } +} diff --git a/app/src/Repository/Persona.php b/app/src/Repository/Persona.php new file mode 100644 index 0000000..774f844 --- /dev/null +++ b/app/src/Repository/Persona.php @@ -0,0 +1,49 @@ +setTable('personas'); + } + + public function create(?array $data = null): Model\Persona + { + $map = (new Implement\Repository\MapperParser(['rut', 'digito', 'nombres'])) + ->register('apellido_paterno', (new Implement\Repository\Mapper())->setProperty('apellidoPaterno')) + ->register('apellido_materno', (new Implement\Repository\Mapper())->setProperty('apellidoMaterno')) + ; + return $this->parseData(new Model\Persona(), $data, $map); + } + public function save(Define\Model $model): Model\Persona + { + $this->saveNew(['rut', 'digito', 'nombres', 'apellido_paterno', 'apellido_materno'], + [$model->rut, $model->digito, $model->nombres, $model->apellidoPaterno, $model->apellidoMaterno]); + return $model; + } + public function edit(Define\Model $model, array $new_data): Model\Persona + { + return $this->update($model, $new_data, ['rut', 'digito', 'nombres', 'apellido_paterno', 'apellido_materno']); + } + + public function fetchByRut(int $rut): Model\Persona + { + $query = $this->connection->getQueryBuilder() + ->select() + ->from($this->getTable()) + ->where('rut = ?'); + return $this->fetchOne($query, [$rut]); + } + + protected function getKey(): string + { + return 'rut'; + } +} diff --git a/app/src/Repository/Sociedad.php b/app/src/Repository/Sociedad.php new file mode 100644 index 0000000..dfc74ed --- /dev/null +++ b/app/src/Repository/Sociedad.php @@ -0,0 +1,55 @@ +setTable('sociedades'); + } + + public function create(?array $data = null): Model\Sociedad + { + $map = (new Implement\Repository\MapperParser(['rut', 'digito', 'nombre'])) + ->register('razon', (new Implement\Repository\Mapper()) + ->setProperty('razonSocial')) + ->register('tipo_sociedad_id', (new Implement\Repository\Mapper()) + ->setProperty('tipoSociedad') + ->setFunction(function ($data) { + return $this->tipoSociedadRepository->fetchById($data['tipo_sociedad_id']); + }) + ) + ->register('contacto_rut', (new Implement\Repository\Mapper()) + ->setProperty('contacto') + ->setFunction(function ($data) { + return $this->personaService->getByRut($data['contacto_rut']); + })); + return $this->parseData(new Model\Sociedad(), $data, $map); + } + public function save(Define\Model $model): Model\Sociedad + { + $this->saveNew(['rut', 'digito', 'nombre', 'razon', 'tipo_sociedad_id', 'contacto_rut'], + [$model->rut, $model->digito, $model->nombre, $model->razonSocial, $model->tipoSociedad->id, + $model->contacto->rut]); + return $model; + } + public function edit(Define\Model $model, array $new_data): Model\Sociedad + { + return $this->update($model, + ['digito', 'nombre', 'razon', 'tipo_sociedad_id', 'contacto_rut'], $new_data); + } + + protected function getKey(): string + { + return 'rut'; + } +} diff --git a/app/src/Repository/Venta/Factura.php b/app/src/Repository/Venta/Factura.php new file mode 100644 index 0000000..0bd8716 --- /dev/null +++ b/app/src/Repository/Venta/Factura.php @@ -0,0 +1,129 @@ +setTable('facturas'); + } + + public function create(?array $data = null): Model\Venta\Factura + { + $map = (new Implement\Repository\MapperParser(['index'])) + ->register('venta_id', (new Implement\Repository\Mapper()) + ->setProperty('venta') + ->setFunction(function($data) { + return $this->ventaRepository->fetchById($data['venta_id']); + })); + $factura = $this->parseData(new Model\Venta\Factura(), $data, $map); + $json = json_decode($data['data']); + $factura->proporcion = $json->proporcion; + $factura->emisorRut = $json->emisor->rut; + $factura->emisorNombre = $json->emisor->nombre; + $factura->emisorDireccion = $json->emisor->direccion; + $factura->receptorRut = $json->receptor->rut; + $factura->receptorNombre = $json->receptor->nombre; + $factura->receptorDireccion = $json->receptor->direccion; + $factura->receptorComuna = $json->receptor->comuna; + $factura->fecha = new DateTimeImmutable($json->fecha); + $factura->unidades = $json->unidades; + $factura->detalleBase = $json->detalle->base; + $factura->detalleTerreno = $json->detalle->terreno; + $factura->detalleNeto = $json->detalle->neto; + $factura->detalleIva = $json->detalle->iva; + $factura->detalleBruto = $json->detalle->bruto; + $factura->detalleDescuento = $json->detalle->descuento; + $factura->detalleTotal = $json->detalle->total; + $factura->totalNeto = $json->total->neto; + $factura->totalExento = $json->total->exento; + $factura->totalIva = $json->total->iva; + $factura->totalTotal = $json->total->total; + $factura->fechaUF = new DateTimeImmutable($json->uf->fecha); + $factura->valorUF = $json->uf->valor; + return $factura; + } + public function save(Define\Model $model): Model\Venta\Factura + { + $model->id = $this->saveNew([ + 'venta_id', + 'index', + 'data' + ], [ + $model->venta->id, + $model->index, + json_encode([ + 'proporcion' => $model->proporcion, + 'emisor' => [ + 'rut' => $model->emisorRut, + 'nombre' => $model->emisorNombre, + 'direccion' => $model->emisorDireccion + ], + 'receptor' => [ + 'rut' => $model->receptorRut, + 'nombre' => $model->receptorNombre, + 'direccion' => $model->receptorDireccion, + 'comuna' => $model->receptorComuna + ], + 'fecha' => $model->fecha->format('Y-m-d'), + 'unidades' => $model->unidades, + 'detalle' => [ + 'base' => $model->detalleBase, + 'terreno' => $model->detalleTerreno, + 'neto' => $model->detalleNeto, + 'iva' => $model->detalleIva, + 'bruto' => $model->detalleBruto, + 'descuento' => $model->detalleDescuento, + 'total' => $model->detalleTotal + ], + 'total' => [ + 'neto' => $model->totalNeto, + 'exento' => $model->totalExento, + 'iva' => $model->totalIva, + 'total' => $model->totalTotal + ], + 'uf' => [ + 'fecha' => $model->fechaUF->format('Y-m-d'), + 'valor' => $model->valorUF + ] + ]) + ]); + return $model; + } + public function edit(Define\Model $model, array $new_data): Model\Venta\Factura + { + return $this->update($model, ['venta_id', 'index', 'data'], $new_data); + } + + /** + * @throws EmptyResult + */ + public function fetchByVenta(int $venta_id): array + { + $query = $this->connection->getQueryBuilder() + ->select() + ->from($this->getTable()) + ->where('venta_id = :venta_id'); + return $this->fetchMany($query, ['venta_id' => $venta_id]); + } + /** + * @throws EmptyResult + */ + public function fetchByVentaAndIndex(int $venta_id, int $index): Model\Venta\Factura + { + $query = $this->connection->getQueryBuilder() + ->select() + ->from($this->getTable()) + ->where('venta_id = :venta_id AND index = :index'); + return $this->fetchOne($query, ['venta_id' => $venta_id, 'index' => $index]); + } +} diff --git a/app/src/Repository/Venta/Factura/Estado.php b/app/src/Repository/Venta/Factura/Estado.php new file mode 100644 index 0000000..a12ea53 --- /dev/null +++ b/app/src/Repository/Venta/Factura/Estado.php @@ -0,0 +1,60 @@ +setTable('estados_facturas'); + } + + public function create(?array $data = null): Model\Venta\Factura\Estado + { + $map = (new Implement\Repository\MapperParser()) + ->register('factura_id', (new Implement\Repository\Mapper()) + ->setProperty('factura') + ->setFunction(function($data) { + return $this->facturaRepository->fetchById($data['factura_id']); + })) + ->register('fecha', new Implement\Repository\Mapper\DateTime('fecha')) + ->register('tipo_id', (new Implement\Repository\Mapper()) + ->setProperty('tipo') + ->setFunction(function($data) { + return $this->tipoRepository->fetchById($data['tipo_id']); + })); + return $this->parseData(new Model\Venta\Factura\Estado(), $data, $map); + } + public function save(Define\Model $model): Model\Venta\Factura\Estado + { + $model->id = $this->saveNew([ + 'factura_id', + 'fecha', + 'tipo_id' + ], [ + $model->factura->id, + $model->fecha->format('Y-m-d'), + $model->tipo->id + ]); + return $model; + } + public function edit(Define\Model $model, array $new_data): Model\Venta\Factura\Estado + { + return $this->update($model, ['factura_id', 'fecha', 'tipo_id'], $new_data); + } + + public function fetchByFactura(int $factura_id): array + { + $query = $this->connection->getQueryBuilder() + ->select() + ->from($this->getTable()) + ->where('factura_id = :factura_id'); + return $this->fetchMany($query, ['factura_id' => $factura_id]); + } +} diff --git a/app/src/Repository/Venta/Factura/Estado/Tipo.php b/app/src/Repository/Venta/Factura/Estado/Tipo.php new file mode 100644 index 0000000..4206fb4 --- /dev/null +++ b/app/src/Repository/Venta/Factura/Estado/Tipo.php @@ -0,0 +1,17 @@ +rut = $this->saveNew( ['rut', 'dv', 'nombres', 'apellido_paterno', 'apellido_materno', 'direccion', 'otro', 'representante'], - [$model->rut, $model->dv, $model->nombres, $model->apellidos['paterno'], $model->apellidos['materno'], $model->datos->direccion->id, $model->otro->rut ?? 0, $model->representante->rut ?? 0] + [$model->rut, $model->dv, $model->nombres, $model->apellidos['paterno'], $model->apellidos['materno'], $model->datos->direccion->id, $model->otro->rut ?? 0, $model->contacto->rut ?? 0] ); return $model; } diff --git a/app/src/Service/Contabilidad.php b/app/src/Service/Contabilidad.php index a5e87fd..692fe72 100644 --- a/app/src/Service/Contabilidad.php +++ b/app/src/Service/Contabilidad.php @@ -15,6 +15,6 @@ class Contabilidad extends Ideal\Controller public function tesoreria(DateTimeInterface $fecha): array { - return $this->tesoreriaService->build($fecha); + return $this->tesoreriaService->getOutput()->build($fecha); } } diff --git a/app/src/Service/Contabilidad/Cartola.php b/app/src/Service/Contabilidad/Cartola.php index 8b3cb76..cd19242 100644 --- a/app/src/Service/Contabilidad/Cartola.php +++ b/app/src/Service/Contabilidad/Cartola.php @@ -121,9 +121,10 @@ class Cartola extends Service { try { return $this->movimientoRepository - ->fetchByCuentaAndFechaAndCargoAndAbonoAndSaldo( + ->fetchByCuentaAndFechaAndGlosaAndCargoAndAbonoAndSaldo( $cuenta->id, new DateTimeImmutable($data['fecha']), + $data['glosa'], $data['cargo'] ?? 0, $data['abono'] ?? 0, $data['saldo'] diff --git a/app/src/Service/Contabilidad/Cartola/BCI.php b/app/src/Service/Contabilidad/Cartola/BCI.php index dc3b8ab..54ee427 100644 --- a/app/src/Service/Contabilidad/Cartola/BCI.php +++ b/app/src/Service/Contabilidad/Cartola/BCI.php @@ -14,7 +14,13 @@ class BCI extends Banco 'Cargo $ (-)' => 'cargo', 'Abono $ (+)' => 'abono', 'Descripción' => 'glosa', - 'Saldo' => 'saldo' + 'Saldo' => 'saldo', + 'Categoría' => 'categoria', + 'Centro costos' => 'centro_costo', + 'Detalle' => 'detalle', + 'Factura Boleta' => 'identificador', + 'RUT' => 'rut', + 'Nombres' => 'nombres', ]; } protected function getFilename(UploadedFileInterface $uploadedFile): string diff --git a/app/src/Service/Contabilidad/Cartola/Itau.php b/app/src/Service/Contabilidad/Cartola/Itau.php index 4639ad5..17bc111 100644 --- a/app/src/Service/Contabilidad/Cartola/Itau.php +++ b/app/src/Service/Contabilidad/Cartola/Itau.php @@ -26,7 +26,14 @@ class Itau extends Banco 'Giros o cargos' => 'cargo', 'Documentos' => 'documento', 'Movimientos' => 'glosa', - 'Saldos' => 'saldo' + 'Saldos' => 'saldo', + 'Categoría' => 'categoria', + 'Centro costo' => 'centro_costo', + 'Detalle' => 'detalle', + 'Factura Boleta' => 'identificador', + 'RUT' => 'rut', + 'Nombres' => 'nombres', + 'Depto' => 'identificador', ]; } protected function getFilename(UploadedFileInterface $uploadedFile): string diff --git a/app/src/Service/Contabilidad/Cartola/Santander.php b/app/src/Service/Contabilidad/Cartola/Santander.php index 8b6c7ab..d2f6d8b 100644 --- a/app/src/Service/Contabilidad/Cartola/Santander.php +++ b/app/src/Service/Contabilidad/Cartola/Santander.php @@ -20,7 +20,13 @@ class Santander extends Banco 'Cargo ($)' => 'cargo', 'Abono ($)' => 'abono', 'Descripcin' => 'glosa', - 'Saldo Diario' => 'saldo' + 'Saldo Diario' => 'saldo', + 'Categoría' => 'categoria', + 'Centro costos' => 'centro_costo', + 'Detalle' => 'detalle', + 'Factura Boleta' => 'identificador', + 'RUT' => 'rut', + 'Nombres' => 'nombres', ]; } protected function getFilename(UploadedFileInterface $uploadedFile): string diff --git a/app/src/Service/Contabilidad/Cartola/Security.php b/app/src/Service/Contabilidad/Cartola/Security.php index f2798b4..c36c9a9 100644 --- a/app/src/Service/Contabilidad/Cartola/Security.php +++ b/app/src/Service/Contabilidad/Cartola/Security.php @@ -41,7 +41,14 @@ class Security extends Banco 'nº documento' => 'documento', 'cargos' => 'cargo', 'abonos' => 'abono', - 'saldos' => 'saldo' + 'saldos' => 'saldo', + 'categoría' => 'categoria', + 'centro costos' => 'centro_costo', + 'detalle' => 'detalle', + 'factura boleta' => 'identificador', + 'rut' => 'rut', + 'nombres' => 'nombres', + 'depto' => 'identificador', ]; } diff --git a/app/src/Service/Contabilidad/Informe/Semanal.php b/app/src/Service/Contabilidad/Informe/Semanal.php new file mode 100644 index 0000000..1c0ff7d --- /dev/null +++ b/app/src/Service/Contabilidad/Informe/Semanal.php @@ -0,0 +1,36 @@ +anterior)) { + $this->anterior = $fecha->sub(new DateInterval('P1D')); + if ($this->anterior->format('N') === '7') { + $this->anterior = $fecha->sub(new DateInterval('P3D')); + } + } + return $this->anterior; + } + public function build(DateTimeInterface $fecha): array + {} +} diff --git a/app/src/Service/Contabilidad/Informe/Tesoreria.php b/app/src/Service/Contabilidad/Informe/Tesoreria.php index 5bc8e56..937ae59 100644 --- a/app/src/Service/Contabilidad/Informe/Tesoreria.php +++ b/app/src/Service/Contabilidad/Informe/Tesoreria.php @@ -1,378 +1,23 @@ movimientos = new class(self::ORDEN_SOCIEDADES) { - public function __construct(protected array $ordenSociedades) - { - $this->dap = new class() - { - public array $ingresos = []; - public array $egresos = []; - }; - } - public object $dap; - public array $ingresos = []; - public array $egresos = []; - - const INGRESOS = 'ingresos'; - const EGRESOS = 'egresos'; - public function addDap(string $tipo, array $movimientos) - { - foreach ($movimientos as $movimiento) { - $this->dap->{$tipo} []= $movimiento; - } - return $this; - } - public function updateDap(object $movimiento): void - { - foreach ($this->ingresos as $ingreso) { - if ($movimiento->cuenta->inmobiliaria->rut !== $ingreso->cuenta->inmobiliaria->rut) { - continue; - } - if ($movimiento->fecha->format('Y-m-d') !== $ingreso->fecha->format('Y-m-d')) { - continue; - } - if ($movimiento->documento !== $ingreso->documento) { - continue; - } - $ingreso->glosa = $movimiento->glosa; - break; - } - } - public function build(): array - { - $this->dap->ingresos = $this->sortBySociedades($this->dap->ingresos); - $this->dap->egresos = $this->sortBySociedades($this->dap->egresos); - $this->ingresos = $this->sortBySociedades($this->ingresos); - $this->egresos = $this->sortBySociedades($this->egresos); - return [ - 'capital dap' => [ - 'ingresos' => $this->dap->ingresos, - 'egresos' => $this->dap->egresos - ], - 'ingresos' => $this->ingresos, - 'egresos' => $this->egresos - ]; - } - - private function sortBySociedades(array $movimientos): array - { - $temp = []; - foreach ($this->ordenSociedades as $sociedad_rut) { - $date = null; - foreach ($movimientos as $movimiento) { - if ($date === null) { - $date = $movimiento->fecha; - } - if ($movimiento->fecha !== $date) { - if ($movimiento->cuenta->inmobiliaria->rut === $sociedad_rut) { - $temp []= $movimiento; - } - $date = $movimiento->fecha; - continue; - } - if ($movimiento->cuenta->inmobiliaria->rut === $sociedad_rut) { - $temp []= $movimiento; - } - } - } - foreach ($movimientos as $movimiento) { - if (!in_array($movimiento, $temp)) { - $temp []= $movimiento; - } - } - return $temp; - } - }; - $this->totales = new class() { - public int $anterior = 0; - public int $actual = 0; - public int $ffmm = 0; - public int $deposito = 0; - public int $saldo = 0; - - public function diferencia(): int - { - return $this->actual - $this->anterior; - } - public function saldo(): int - { - return $this->diferencia() + $this->ffmm + $this->deposito; - } - public function cuentas(): int - { - return $this->actual; - } - public function ffmms(): int - { - return $this->ffmm; - } - public function depositos(): int - { - return $this->deposito; - } - public function caja(): int - { - return $this->cuentas() + $this->ffmms() + $this->depositos(); - } - }; } - - const DAP_INGRESOS = 'dap->ingresos'; - const DAP_EGRESOS = 'dap->egresos'; - const INGRESOS = 'ingresos'; - const EGRESOS = 'egresos'; - const TOTAL_ANTERIOR = 'anterior'; - const TOTAL_ACTUAL = 'actual'; - const TOTAL_FFMM = 'ffmm'; - const TOTAL_DAP = 'deposito'; - - protected DateTimeInterface $anterior; - protected object $totales; - protected object $movimientos; - - public function getAnterior(DateTimeInterface $fecha): DateTimeInterface + public function getOutput(): Tesoreria\Output { - if (!isset($this->anterior)) { - $this->anterior = $fecha->sub(new DateInterval('P1D')); - if ($this->anterior->format('N') === '7') { - $this->anterior = $fecha->sub(new DateInterval('P3D')); - } - } - return $this->anterior; + return $this->outputService; } - public function build(DateTimeInterface $fecha): array + public function getInput(): Tesoreria\Input { - try { - $inmobiliarias = $this->inmobiliariaRepository->fetchAll(); - } catch (Implement\Exception\EmptyResult) { - return []; - } - $temp = []; - foreach (self::ORDEN_SOCIEDADES as $sociedad_rut) { - foreach ($inmobiliarias as $inmobiliaria) { - if ($inmobiliaria->rut === $sociedad_rut) { - $temp []= $inmobiliaria; - } - } - } - foreach ($inmobiliarias as $inmobiliaria) { - if (!in_array($inmobiliaria, $temp)) { - $temp []= $inmobiliaria; - } - } - $informe = ['inmobiliarias' => []]; - foreach ($temp as $inmobiliaria) { - $informe['inmobiliarias'][$inmobiliaria->rut] = $this->buildInmobiliaria($inmobiliaria, $fecha); - } - $informe['movimientos'] = $this->buildMovimientos(); - $informe['totales'] = $this->buildTotales(); - - //$this->buildInforme($fecha, $informe); - - return $informe; - } - public function buildInforme(DateTimeInterface $fecha, array $data, string $type = 'Xlsx', ?string $filename = 'php://output'): void - { - $informe = $this->excelService->build($fecha, $data); - $this->excelService->save($fecha, $informe, $type, $filename); - } - - protected function buildInmobiliaria(Model\Inmobiliaria $inmobiliaria, DateTimeInterface $fecha): object - { - $dataInmobiliaria = new class() { - public Model\Inmobiliaria $inmobiliaria; - public array $cuentas = []; - public function total(): int - { - return array_reduce($this->cuentas, function(int $sum, $cuenta) { - return $sum + $cuenta->actual; - }, 0); - } - public function ffmm(): int - { - return array_reduce($this->cuentas, function(int $sum, $cuenta) { - return $sum + $cuenta->ffmm; - }, 0); - } - public function deposito(): int - { - return array_reduce($this->cuentas, function(int $sum, $cuenta) { - return $sum + $cuenta->deposito; - }, 0); - } - public function caja(): int - { - return array_reduce($this->cuentas, function(int $sum, $cuenta) { - return $sum + $cuenta->saldo(); - }, 0); - } - }; - $dataInmobiliaria->inmobiliaria = $inmobiliaria; - try { - $cuentas = $this->cuentaService->getAllActiveByInmobiliaria($inmobiliaria->rut); - } catch (Implement\Exception\EmptyResult) { - return $dataInmobiliaria; - } - foreach ($cuentas as $cuenta) { - $data = new class() { - public string $banco; - public string $numero; - public int $anterior = 0; - public int $actual = 0; - public int $ffmm = 0; - public int $deposito = 0; - - public function diferencia(): int - { - return $this->actual - $this->anterior; - } - public function saldo(): int - { - return $this->diferencia() + $this->ffmm + $this->deposito; - } - }; - $data->banco = $cuenta->banco->nombre; - $data->numero = $cuenta->cuenta; - try { - $depositos = $this->depositoRepository->fetchByCuenta($cuenta->id); - foreach ($depositos as $deposito) { - if ($deposito->termino < $fecha) { - continue; - } - $data->deposito += $deposito->capital; - $this->addTotal(self::TOTAL_DAP, $deposito->capital); - $this->totales->saldo += $deposito->capital; - - if ($deposito->inicio->format('Y-m-d') === $fecha->format('Y-m-d')) { - $this->addMovimientos(self::DAP_EGRESOS, [(object) [ - 'cuenta' => $deposito->cuenta, - 'fecha' => $deposito->inicio, - 'cargo' => - $deposito->capital, - 'abono' => 0, - 'saldo' => - $deposito->capital, - 'glosa' => 'INVERSION DAP' - ]]); - } - if ($deposito->termino->format('Y-m-d') === $fecha->format('Y-m-d')) { - $data->deposito -= $deposito->capital; - $this->addTotal(self::TOTAL_DAP, -$deposito->capital); - - $this->addMovimientos(self::INGRESOS, [(object) [ - 'cuenta' => $deposito->cuenta, - 'fecha' => $deposito->termino, - 'cargo' => 0, - 'abono' => $deposito->futuro - $deposito->capital, - 'saldo' => $deposito->futuro - $deposito->capital, - 'glosa' => 'RESCATE DAP', - 'documento' => $deposito->id - ]]); - } - } - } catch (Implement\Exception\EmptyResult) {} - $anterior = $this->getAnterior($fecha); - try { - $cartola = $this->cartolaRepository->fetchLastByCuentaAndFecha($cuenta->id, $fecha); - $data->actual = $cartola->saldo; - //$anterior = $this->getAnterior($cartola->fecha); - } catch (Implement\Exception\EmptyResult) {} - try { - $cartola = $this->cartolaRepository->fetchLastByCuentaAndFecha($cuenta->id, $anterior); - $data->anterior = $cartola->saldo; - $this->totales->saldo += $cartola->saldo; - } catch (Implement\Exception\EmptyResult) {} - if ($data->diferencia() !== 0) { - try { - $movimientos = $this->movimientoRepository->fetchByCuentaAndFecha($cuenta->id, $fecha); - $this->addMovimientos(self::INGRESOS, - array_filter($movimientos, function(Model\Contabilidad\Movimiento $movimiento) { - return $movimiento->abono > 0; - })); - $this->addMovimientos(self::EGRESOS, - array_filter($movimientos, function(Model\Contabilidad\Movimiento $movimiento) { - return $movimiento->cargo > 0; - })); - } catch (Implement\Exception\EmptyResult) {} - } - $dataInmobiliaria->cuentas []= $data; - - $this->addTotal( - [self::TOTAL_ANTERIOR, self::TOTAL_ACTUAL], - [$data->anterior, $data->actual] - ); - } - - return $dataInmobiliaria; - } - protected function buildMovimientos(): array - { - return $this->movimientos->build(); - } - protected function buildTotales(): object - { - return $this->totales; - } - protected function addMovimientos(string $tipo, array $movimientos): Tesoreria - { - if (str_starts_with($tipo, 'dap')) { - list($d, $t) = explode('->', $tipo); - $this->movimientos->addDap($t, $movimientos); - return $this; - } - foreach ($movimientos as $movimiento) { - if ($tipo === 'ingresos' and str_contains(strtolower($movimiento->glosa), ' dap ')) { - $this->movimientos->updateDap($movimiento); - continue; - } - $this->movimientos->{$tipo} []= $movimiento; - } - return $this; - } - protected function addTotal(string|array $tipo, int|array $total): Tesoreria - { - if (is_array($tipo)) { - foreach ($tipo as $i => $t) { - $this->addTotal($t, $total[$i]); - } - return $this; - } - $this->totales->{$tipo} += $total; - return $this; + return $this->inputService; } } diff --git a/app/src/Service/Contabilidad/Informe/Tesoreria/Input.php b/app/src/Service/Contabilidad/Informe/Tesoreria/Input.php new file mode 100644 index 0000000..4b65e1f --- /dev/null +++ b/app/src/Service/Contabilidad/Informe/Tesoreria/Input.php @@ -0,0 +1,36 @@ +getSize() === 0) { + return []; + } + $tmpFile = '/tmp/' . $uploadedFile->getClientFilename(); + $uploadedFile->moveTo($tmpFile); + $data = $this->excelService->load($tmpFile); + unlink($tmpFile); + + return $data; + } + + public function load(array $data): void + { + $this->saldosContablesService->load($data['saldosContables']); + $this->dapYFFMMService->load($data['dapyffmm']); + } +} diff --git a/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Data/DAPyFFMM.php b/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Data/DAPyFFMM.php new file mode 100644 index 0000000..fb5b57c --- /dev/null +++ b/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Data/DAPyFFMM.php @@ -0,0 +1,12 @@ +logger->error('Cargando DAP y FFMM', $data); + } +} diff --git a/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Data/SaldosContables.php b/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Data/SaldosContables.php new file mode 100644 index 0000000..12f1b61 --- /dev/null +++ b/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Data/SaldosContables.php @@ -0,0 +1,152 @@ +data = $data['movimientos']; + foreach ($data['movimientos'] as $type => $dataMovimiento) { + switch ($type) { + case 'total': + $this->saldoInicial = $dataMovimiento; + break; + case 'depositos': + $this->loadDepositos($dataMovimiento); + break; + case 'egresos': + case 'ingresos': + $this->loadMovimiento($dataMovimiento); + break; + } + } + } + + protected array $sociedades; + protected int $saldoInicial; + protected array $data; + + protected function loadDepositos(array $data): void + { + $this->logger->error('Cargando depositos', $data); + } + protected function loadMovimiento(array $data): void + { + $sociedades = $this->getSociedades(); + $unmatched = []; + foreach ($data as $dataMovimiento) { + try { + $sociedad_rut = $this->matchSociedad($sociedades, $dataMovimiento->empresa); + $banco = $this->bancoRepository->fetchByNombre($dataMovimiento->banco); + $cuenta = $this->cuentaRepository->fetchByInmobiliariaAndBanco($sociedad_rut, $banco->id); + $data = [ + 'cuenta_id' => $cuenta->id, + 'fecha' => $dataMovimiento->fecha->format('Y-m-d'), + 'glosa' => mb_convert_encoding($dataMovimiento->{'descripción'}, 'UTF-8'), + 'documento' => $dataMovimiento->{'n°Doc'}, + 'cargo' => -$dataMovimiento->egresos, + 'abono' => $dataMovimiento->ingresos, + 'saldo' => $this->getSaldo($dataMovimiento) + ]; + try { + $movimiento = $this->movimientoRepository->fetchByCuentaAndFechaAndCargoAndAbonoAndSaldo($cuenta->id, $dataMovimiento->fecha, $data['cargo'], $data['abono'], $data['saldo']); + } catch (Implement\Exception\EmptyResult) { + $movimiento = $this->movimientoRepository->create($data); + $movimiento = $this->movimientoRepository->save($movimiento); + } + list($rut, $digito) = explode('-', $dataMovimiento->rut); + $data = [ + 'movimiento_id' => $movimiento->id, + 'centro_costo_id' => $dataMovimiento->cc, + 'rut' => (int) preg_replace('/\D*/', '', $rut), + 'digito' => $digito, + 'nombre' => $dataMovimiento->nombres, + 'categoria' => $dataMovimiento->categoria, + 'detalle' => $dataMovimiento->detalle, + ]; + if ($data['centro_costo_id'] === 0 and ($data['rut'] === 0 or $data['nombre'] === '' or $data['categoria'] === '' or $data['detalle'] === '')) { + continue; + } + try { + $detalles = $this->detalleRepository->fetchByMovimiento($movimiento->id); + $this->detalleRepository->edit($detalles, $data); + } catch (Implement\Exception\EmptyResult) { + $detalles = $this->detalleRepository->create($data); + $this->detalleRepository->save($detalles); + } + } catch (Exception $exception) { + $this->logger->error($exception); + $unmatched []= $dataMovimiento; + } + } + + if (count($unmatched) > 0) { + $this->logger->error('Movimientos no asociados', $unmatched); + } + } + + protected function getSociedades(): array + { + if (!isset($this->sociedades)) { + $this->sociedades = []; + try { + $this->sociedades = $this->inmobiliariaRepository->fetchAll(); + } catch (Implement\Exception\EmptyResult $e) { + $this->logger->error($e->getMessage()); + } + } + return $this->sociedades; + } + protected function getSaldo($movimiento): int + { + $saldo = $this->saldoInicial; + foreach ($this->data as $type => $dataMovimientos) { + if (in_array($type, ['total', 'depositos'])) { + continue; + } + foreach ($dataMovimientos as $dataMovimiento) { + if ($dataMovimiento !== $movimiento) { + continue; + } + $saldo += $dataMovimiento->ingresos + $dataMovimiento->egresos; + } + } + return $saldo; + } + protected function matchSociedad(array $sociedades, string $name): int + { + foreach ($sociedades as $sociedad) { + $abreviacion = $sociedad->abreviacion; + if ($abreviacion === 'Incoviba') { + if (preg_match('/(Vial Balmaceda)+/', $name) === 1) { + return $sociedad->rut; + } + continue; + } + if (str_contains($abreviacion, 'Optimus')) { + $abreviacion = 'Óptimus'; + } + if (preg_match("/({$abreviacion})+/", $name) === 1) { + return $sociedad->rut; + } + } + + throw new Exception("No se encontró la sociedad asociada al nombre '{$name}'"); + } +} diff --git a/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Excel.php b/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Excel.php new file mode 100644 index 0000000..e9262d2 --- /dev/null +++ b/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Excel.php @@ -0,0 +1,35 @@ +logger->error($e->getMessage()); + return []; + } + $excel = $reader->load($filename); + + $data = []; + $data['saldosContables'] = $this->saldosCuentasService->load($excel); + $data['dapyffmm'] = $this->dapyFFMMService->load($excel); + $data['deudaBanco'] = $this->deudaBancoService->load($excel); + + return $data; + } +} diff --git a/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Excel/DAPyFFMM.php b/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Excel/DAPyFFMM.php new file mode 100644 index 0000000..c6623a0 --- /dev/null +++ b/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Excel/DAPyFFMM.php @@ -0,0 +1,51 @@ +sheetNameExists('DAP y FFMM')) { + return []; + } + $sheet = $excel->getSheetByName('DAP y FFMM'); + $data = []; + + $rowIndex = 1; + while ($sheet->getCell("B{$rowIndex}")->getValue() !== 'EMPRESA') { + $rowIndex ++; + } + $titleRow = $rowIndex; + $columnOffset = 2; + $titles = $this->getTableTitles($sheet, $titleRow, $columnOffset, 20, 'UF', ['(']); + + $rowIndex ++; + while ($sheet->getCell("B{$rowIndex}")->getValue() !== 'TOTAL') { + if ($sheet->getCell("B{$rowIndex}")->getValue() !== null) { + $data []= $this->getRow($sheet, $titles, $titleRow, $rowIndex, $columnOffset); + /* + $dap = []; + $columnIndex = 0; + $dap[$titles[$columnIndex ++]] = $sheet->getCell("B{$rowIndex}")->getValue(); + $dap[$titles[$columnIndex ++]] = $sheet->getCell("D{$rowIndex}")->getValue(); + $dap[$titles[$columnIndex ++]] = $sheet->getCell("F{$rowIndex}")->getValue(); + $dap[$titles[$columnIndex ++]] = $this->getCalculatedValue($sheet, 'H', $rowIndex); + $dap[$titles[$columnIndex ++]] = $this->getCalculatedValue($sheet, 'I', $rowIndex); + $dap[$titles[$columnIndex ++]] = $this->getCalculatedValue($sheet, 'J', $rowIndex); + $dap[$titles[$columnIndex ++]] = $this->getCalculatedValue($sheet, 'K', $rowIndex); + $dap[$titles[$columnIndex ++]] = PhpSpreadsheet\Shared\Date::excelToDateTimeObject($this->getCalculatedValue($sheet, 'L', $rowIndex)); + $dap[$titles[$columnIndex ++]] = PhpSpreadsheet\Shared\Date::excelToDateTimeObject($this->getCalculatedValue($sheet, 'M', $rowIndex)); + $dap[$titles[$columnIndex ++]] = $this->getCalculatedValue($sheet, 'N', $rowIndex); + $dap[$titles[$columnIndex]] = $this->getCalculatedValue($sheet, 'O', $rowIndex); + + $data []= (object) $dap;*/ + } + $rowIndex ++; + } + + return $data; + } +} diff --git a/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Excel/DeudaBanco.php b/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Excel/DeudaBanco.php new file mode 100644 index 0000000..764b2a3 --- /dev/null +++ b/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Excel/DeudaBanco.php @@ -0,0 +1,34 @@ +sheetNameExists('Deuda Banco')) { + return []; + } + $sheet = $excel->getSheetByName('Deuda Banco'); + $data = []; + + $rowIndex = 1; + $columnOffset = 2; + while ($sheet->getCell([$columnOffset, $rowIndex])->getValue() !== 'EMPRESA') { + $rowIndex ++; + } + $titleRow = $rowIndex; + $titles = $this->getTableTitles($sheet, $titleRow, $columnOffset, 13, 'UF', ['(']); + $rowIndex ++; + + while ($sheet->getCell([$columnOffset, $rowIndex])->getValue() !== 'TOTAL GRUPO EMPRESAS') { + if ($sheet->getCell([$columnOffset, $rowIndex])->getValue() !== null) { + $data []= $this->getRow($sheet, $titles, $titleRow, $rowIndex, $columnOffset); + } + $rowIndex ++; + } + + return $data; + } +} diff --git a/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Excel/SaldosCuentas.php b/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Excel/SaldosCuentas.php new file mode 100644 index 0000000..041ef60 --- /dev/null +++ b/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Excel/SaldosCuentas.php @@ -0,0 +1,109 @@ +sheetNameExists('Saldos cuentas')) { + return []; + } + $sheet = $excel->getSheetByName('Saldos cuentas'); + $data = []; + $data['anterior'] = PhpSpreadsheet\Shared\Date::excelToDateTimeObject($this->getCalculatedValue($sheet, 'C4')); + $data['actual'] = PhpSpreadsheet\Shared\Date::excelToDateTimeObject($this->getCalculatedValue($sheet, 'C5')); + $data['uf'] = $this->getCalculatedValue($sheet, 'F4'); + $data['usd'] = $this->getCalculatedValue($sheet, 'F5'); + + $titleRow = 7; + $data['sociedades'] = $this->getSociedades($sheet, $titleRow); + + $titleRow += count($data['sociedades']); + while ($sheet->getCell("B{$titleRow}")->getValue() !== 'EMPRESA') { + $titleRow ++; + } + $data['movimientos'] = $this->getMovimientos($sheet, $titleRow); + + return $data; + } + + protected function getSociedades(PhpSpreadsheet\Worksheet\Worksheet $sheet, int $titleRow = 7, int $startColumn = 2): array + { + $totalsColumn = $startColumn; + while ($sheet->getCell([$totalsColumn, $titleRow])->getValue() !== null && $sheet->getCell([$totalsColumn, $titleRow])->getValue() !== 'Total Cuentas') { + $totalsColumn ++; + } + $rowIndex = $titleRow + 1; + $sociedades = []; + while ($rowIndex < 100 and $sheet->getCell("B{$rowIndex}")->getValue() !== 'TOTAL') { + $sociedad = new stdClass(); + $sociedad->razon = $sheet->getCell("B{$rowIndex}")->getValue(); + $sociedad->cuentas = []; + $cuentaColumnIndex = 3; + $cuenta = new stdClass(); + while ($cuentaColumnIndex < $totalsColumn) { + $cuenta->banco = $sheet->getCell([$cuentaColumnIndex ++, $rowIndex])->getValue() ?? ''; + $cuenta->numero = $sheet->getCell([$cuentaColumnIndex ++, $rowIndex])->getValue() ?? ''; + $cuenta->anterior = $this->getCalculatedValue($sheet, $cuentaColumnIndex ++, $rowIndex); + $cuenta->actual = $this->getCalculatedValue($sheet, $cuentaColumnIndex ++, $rowIndex); + $cuenta->diferencia = $this->getCalculatedValue($sheet, $cuentaColumnIndex ++, $rowIndex); + $cuenta->ffmm = $this->getCalculatedValue($sheet, $cuentaColumnIndex ++, $rowIndex); + $cuenta->deposito = $this->getCalculatedValue($sheet, $cuentaColumnIndex ++, $rowIndex); + $cuenta->saldo = $this->getCalculatedValue($sheet, $cuentaColumnIndex ++, $rowIndex); + + $sociedad->cuentas []= $cuenta; + + if ($sheet->getCell([$cuentaColumnIndex, $rowIndex])->getValue() === null) { + break; + } + $cuenta = new stdClass(); + } + $sociedades []= $sociedad; + $rowIndex ++; + } + return $sociedades; + } + protected function getMovimientos(PhpSpreadsheet\Worksheet\Worksheet $sheet, int $titleRow, int $startColumn = 2): array + { + $data = []; + $titles = $this->getTableTitles($sheet, $titleRow, $startColumn, 15); + + $totalRow = $titleRow + 2; + $data['total'] = $this->getCalculatedValue($sheet, "V{$totalRow}"); + $rowIndex = $titleRow + 4; + $depositos = []; + while ($sheet->getCell("B{$rowIndex}")->getValue() !== 'INGRESOS') { + if ( $sheet->getCell("B{$rowIndex}")->getValue() !== null) { + $depositos []= $this->getRow($sheet, $titles, $titleRow, $rowIndex, $startColumn); + } + $rowIndex ++; + } + $data['depositos'] = $depositos; + + $rowIndex ++; + $ingresos = []; + while ($sheet->getCell("B{$rowIndex}")->getValue() !== 'EGRESOS') { + if ($sheet->getCell("B{$rowIndex}")->getValue() !== null) { + $ingresos []= $this->getRow($sheet, $titles, $titleRow, $rowIndex, $startColumn); + } + $rowIndex ++; + } + $data['ingresos'] = $ingresos; + + $rowIndex ++; + $egresos = []; + while ($sheet->getCell("B{$rowIndex}")->getValue() !== 'TOTAL') { + if ($sheet->getCell("B{$rowIndex}")->getValue() === null) { + break; + } + $egresos [] = $this->getRow($sheet, $titles, $titleRow, $rowIndex, $startColumn); + $rowIndex ++; + } + $data['egresos'] = $egresos; + + return $data; + } +} diff --git a/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Excel/Sheet.php b/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Excel/Sheet.php new file mode 100644 index 0000000..a0293ef --- /dev/null +++ b/app/src/Service/Contabilidad/Informe/Tesoreria/Input/Excel/Sheet.php @@ -0,0 +1,73 @@ +getCell($columnIndex)->getCalculatedValue() ?? $default; + } + return $sheet->getCell("{$columnIndex}{$rowIndex}")->getCalculatedValue() ?? $default; + } + return $sheet->getCell([$columnIndex, $rowIndex])->getCalculatedValue() ?? $default; + } catch (PhpSpreadsheet\Calculation\Exception $e) { + $this->logger->error($e->getMessage()); + return $default; + } + } + protected function getTableTitles(PhpSpreadsheet\Worksheet\Worksheet $sheet, int $titleRow, int $columnOffset, int $maxColumns, string $duplicateSuffix = '', array $cutoffCharacters = []): array + { + $titles = []; + $columnIndex = $columnOffset; + while ($columnIndex < $maxColumns or $sheet->getCell([$columnIndex, $titleRow])->getValue() !== null) { + if ($sheet->getCell([$columnIndex, $titleRow])->getValue() !== null) { + $title = $this->transformTitle($sheet->getCell([$columnIndex, $titleRow])->getValue(), $cutoffCharacters); + if (in_array($title, $titles)) { + $title .= $duplicateSuffix; + } + $titles []= $title; + } + $columnIndex ++; + } + return $titles; + } + protected function getRow(PhpSpreadsheet\Worksheet\Worksheet $sheet, array $titles, int $titleRow, int $rowIndex, int $columnOffset): object + { + $row = []; + $columnIndex = $columnOffset; + $titleIndex = 0; + $currentTitle = $this->transformTitle($sheet->getCell([$columnIndex, $titleRow])->getValue()); + while ($columnIndex < count($titles) * 3 and $currentTitle !== last($titles)) { + if ($sheet->getCell([$columnIndex, $titleRow])->getValue() === null) { + $columnIndex ++; + continue; + } + if (str_contains($titles[$titleIndex], 'fecha')) { + $row[$titles[$titleIndex ++]] = PhpSpreadsheet\Shared\Date::excelToDateTimeObject($this->getCalculatedValue($sheet, $columnIndex ++, $rowIndex)); + continue; + } + $row[$titles[$titleIndex ++]] = $this->getCalculatedValue($sheet, $columnIndex ++, $rowIndex); + } + + return (object) $row; + } + protected function transformTitle(string $title, array $cutoffCharacters = []): string + { + $title = str_replace(' ', '', ucwords(mb_strtolower($title))); + $title = strtolower(substr($title, 0, 1)) . substr($title, 1); + foreach ($cutoffCharacters as $cutoffCharacter) { + if (str_contains($title, $cutoffCharacter)) { + $title = substr($title, 0, strpos($title, $cutoffCharacter)); + } + } + return $title; + } + + abstract public function load(PhpSpreadsheet\Spreadsheet $excel): array; +} diff --git a/app/src/Service/Contabilidad/Informe/Tesoreria/Output.php b/app/src/Service/Contabilidad/Informe/Tesoreria/Output.php new file mode 100644 index 0000000..c3568fb --- /dev/null +++ b/app/src/Service/Contabilidad/Informe/Tesoreria/Output.php @@ -0,0 +1,226 @@ +ingresos'; + const DAP_EGRESOS = 'dap->egresos'; + const INGRESOS = 'ingresos'; + const EGRESOS = 'egresos'; + const TOTAL_ANTERIOR = 'anterior'; + const TOTAL_ACTUAL = 'actual'; + const TOTAL_FFMM = 'ffmm'; + const TOTAL_DAP = 'deposito'; + + protected DateTimeInterface $anterior; + protected object $totales; + protected object $movimientos; + + public function __construct(LoggerInterface $logger, + protected Repository\Inmobiliaria $inmobiliariaRepository, + protected Repository\Contabilidad\Deposito $depositoRepository, + protected Repository\Contabilidad\Cartola $cartolaRepository, + protected Repository\Contabilidad\Movimiento $movimientoRepository, + protected Service\Inmobiliaria\Cuenta $cuentaService, + protected Output\Excel $excelService, + protected Output\PDF $pdfService) + { + parent::__construct($logger); + + $this->movimientos = new Output\Data\Movimientos(self::ORDEN_SOCIEDADES); + $this->totales = new Output\Data\Totales(); + } + + public function getAnterior(DateTimeInterface $fecha): DateTimeInterface + { + if (!isset($this->anterior)) { + $this->anterior = $fecha->sub(new DateInterval('P1D')); + if ($this->anterior->format('N') === '7') { + $this->anterior = $fecha->sub(new DateInterval('P3D')); + } + } + return $this->anterior; + } + public function build(DateTimeInterface $fecha): array + { + try { + $inmobiliarias = $this->inmobiliariaRepository->fetchAll(); + } catch (Implement\Exception\EmptyResult) { + return []; + } + $data = $this->sortBySociedad($inmobiliarias); + $informe = ['sociedades' => []]; + foreach ($data as $sociedad) { + $informe['sociedades'][$sociedad->rut] = $this->buildInmobiliaria($sociedad, $fecha); + } + $informe['movimientos'] = $this->buildMovimientos(); + $informe['totales'] = $this->buildTotales(); + + //$this->buildInforme($fecha, $informe); + + return $informe; + } + public function buildInforme(DateTimeInterface $fecha, array $data, string $type = 'Xlsx', ?string $filename = 'php://output'): void + { + $informe = $this->excelService->build($fecha, $data); + $this->excelService->save($fecha, $informe, $type, $filename); + } + + protected function buildInmobiliaria(Model\Inmobiliaria $inmobiliaria, DateTimeInterface $fecha): object + { + $dataInmobiliaria = new Output\Data\Sociedad(); + $dataInmobiliaria->sociedad = $inmobiliaria; + try { + $cuentas = $this->cuentaService->getAllActiveByInmobiliaria($inmobiliaria->rut); + } catch (Implement\Exception\EmptyResult) { + return $dataInmobiliaria; + } + foreach ($cuentas as $cuenta) { + $data = new Output\Data\Cuenta(); + $data->banco = $cuenta->banco->nombre; + $data->numero = $cuenta->cuenta; + try { + $depositos = $this->depositoRepository->fetchByCuenta($cuenta->id); + foreach ($depositos as $deposito) { + if ($deposito->termino < $fecha) { + continue; + } + $data->deposito += $deposito->capital; + $this->addTotal(self::TOTAL_DAP, $deposito->capital); + $this->totales->saldo += $deposito->capital; + + if ($deposito->inicio->format('Y-m-d') === $fecha->format('Y-m-d')) { + $this->addMovimientos(self::DAP_EGRESOS, [(object) [ + 'cuenta' => $deposito->cuenta, + 'fecha' => $deposito->inicio, + 'cargo' => - $deposito->capital, + 'abono' => 0, + 'saldo' => - $deposito->capital, + 'glosa' => 'INVERSION DAP' + ]]); + } + if ($deposito->termino->format('Y-m-d') === $fecha->format('Y-m-d')) { + $data->deposito -= $deposito->capital; + $this->addTotal(self::TOTAL_DAP, -$deposito->capital); + + $this->addMovimientos(self::DAP_INGRESOS, [(object) [ + 'cuenta' => $deposito->cuenta, + 'fecha' => $deposito->termino, + 'cargo' => 0, + 'abono' => $deposito->futuro - $deposito->capital, + 'saldo' => $deposito->futuro - $deposito->capital, + 'glosa' => 'RESCATE DAP', + 'documento' => $deposito->id + ]]); + } + } + } catch (Implement\Exception\EmptyResult) {} + $anterior = $this->getAnterior($fecha); + try { + $cartola = $this->cartolaRepository->fetchLastByCuentaAndFecha($cuenta->id, $fecha); + $data->actual = $cartola->saldo; + //$anterior = $this->getAnterior($cartola->fecha); + } catch (Implement\Exception\EmptyResult) {} + try { + $cartola = $this->cartolaRepository->fetchLastByCuentaAndFecha($cuenta->id, $anterior); + $data->anterior = $cartola->saldo; + $this->totales->saldo += $cartola->saldo; + } catch (Implement\Exception\EmptyResult) {} + if ($data->diferencia() !== 0) { + try { + $movimientos = $this->movimientoRepository->fetchByCuentaAndFecha($cuenta->id, $fecha); + $this->addMovimientos(self::INGRESOS, + array_filter($movimientos, function(Model\Contabilidad\Movimiento $movimiento) { + return $movimiento->abono > 0; + })); + $this->addMovimientos(self::EGRESOS, + array_filter($movimientos, function(Model\Contabilidad\Movimiento $movimiento) { + return $movimiento->cargo > 0; + })); + } catch (Implement\Exception\EmptyResult) {} + } + $dataInmobiliaria->cuentas []= $data; + + $this->addTotal( + [self::TOTAL_ANTERIOR, self::TOTAL_ACTUAL], + [$data->anterior, $data->actual] + ); + } + + return $dataInmobiliaria; + } + protected function buildMovimientos(): array + { + return $this->movimientos->build(); + } + protected function buildTotales(): object + { + return $this->totales; + } + protected function addMovimientos(string $tipo, array $movimientos): Output + { + if (str_starts_with($tipo, 'dap')) { + list($d, $t) = explode('->', $tipo); + $this->movimientos->addDap($t, $movimientos); + return $this; + } + foreach ($movimientos as $movimiento) { + if ($tipo === 'ingresos' and str_contains(strtolower($movimiento->glosa), ' dap ')) { + $this->movimientos->updateDap($movimiento); + continue; + } + $this->movimientos->{$tipo} []= $movimiento; + } + return $this; + } + protected function addTotal(string|array $tipo, int|array $total): Output + { + if (is_array($tipo)) { + foreach ($tipo as $i => $t) { + $this->addTotal($t, $total[$i]); + } + return $this; + } + $this->totales->{$tipo} += $total; + return $this; + } + protected function sortBySociedad(array $data): array + { + $temp = []; + foreach (self::ORDEN_SOCIEDADES as $sociedad_rut) { + foreach ($data as $inmobiliaria) { + if ($inmobiliaria->rut === $sociedad_rut) { + $temp []= $inmobiliaria; + } + } + } + foreach ($data as $inmobiliaria) { + if (!in_array($inmobiliaria, $temp)) { + $temp []= $inmobiliaria; + } + } + return $temp; + } +} diff --git a/app/src/Service/Contabilidad/Informe/Tesoreria/Output/Data/Cuenta.php b/app/src/Service/Contabilidad/Informe/Tesoreria/Output/Data/Cuenta.php new file mode 100644 index 0000000..fe951f2 --- /dev/null +++ b/app/src/Service/Contabilidad/Informe/Tesoreria/Output/Data/Cuenta.php @@ -0,0 +1,21 @@ +actual - $this->anterior; + } + public function saldo(): int + { + return $this->diferencia() + $this->ffmm + $this->deposito; + } +} diff --git a/app/src/Service/Contabilidad/Informe/Tesoreria/Output/Data/Movimientos.php b/app/src/Service/Contabilidad/Informe/Tesoreria/Output/Data/Movimientos.php new file mode 100644 index 0000000..00131e3 --- /dev/null +++ b/app/src/Service/Contabilidad/Informe/Tesoreria/Output/Data/Movimientos.php @@ -0,0 +1,87 @@ +dap = new class() + { + public array $ingresos = []; + public array $egresos = []; + }; + } + public object $dap; + public array $ingresos = []; + public array $egresos = []; + + const INGRESOS = 'ingresos'; + const EGRESOS = 'egresos'; + public function addDap(string $tipo, array $movimientos) + { + foreach ($movimientos as $movimiento) { + $this->dap->{$tipo} []= $movimiento; + } + return $this; + } + public function updateDap(object $movimiento): void + { + foreach ($this->ingresos as $ingreso) { + if ($movimiento->cuenta->inmobiliaria->rut !== $ingreso->cuenta->inmobiliaria->rut) { + continue; + } + if ($movimiento->fecha->format('Y-m-d') !== $ingreso->fecha->format('Y-m-d')) { + continue; + } + if ($movimiento->documento !== $ingreso->documento) { + continue; + } + $ingreso->glosa = $movimiento->glosa; + break; + } + } + public function build(): array + { + $this->dap->ingresos = $this->sortBySociedades($this->dap->ingresos); + $this->dap->egresos = $this->sortBySociedades($this->dap->egresos); + $this->ingresos = $this->sortBySociedades($this->ingresos); + $this->egresos = $this->sortBySociedades($this->egresos); + return [ + 'capital dap' => [ + 'ingresos' => $this->dap->ingresos, + 'egresos' => $this->dap->egresos + ], + 'ingresos' => $this->ingresos, + 'egresos' => $this->egresos + ]; + } + + private function sortBySociedades(array $movimientos): array + { + $temp = []; + foreach ($this->ordenSociedades as $sociedad_rut) { + $date = null; + foreach ($movimientos as $movimiento) { + if ($date === null) { + $date = $movimiento->fecha; + } + if ($movimiento->fecha !== $date) { + if ($movimiento->cuenta->inmobiliaria->rut === $sociedad_rut) { + $temp []= $movimiento; + } + $date = $movimiento->fecha; + continue; + } + if ($movimiento->cuenta->inmobiliaria->rut === $sociedad_rut) { + $temp []= $movimiento; + } + } + } + foreach ($movimientos as $movimiento) { + if (!in_array($movimiento, $temp)) { + $temp []= $movimiento; + } + } + return $temp; + } +} diff --git a/app/src/Service/Contabilidad/Informe/Tesoreria/Output/Data/Sociedad.php b/app/src/Service/Contabilidad/Informe/Tesoreria/Output/Data/Sociedad.php new file mode 100644 index 0000000..e28ae8e --- /dev/null +++ b/app/src/Service/Contabilidad/Informe/Tesoreria/Output/Data/Sociedad.php @@ -0,0 +1,34 @@ +cuentas, function(int $sum, $cuenta) { + return $sum + $cuenta->actual; + }, 0); + } + public function ffmm(): int + { + return array_reduce($this->cuentas, function(int $sum, $cuenta) { + return $sum + $cuenta->ffmm; + }, 0); + } + public function deposito(): int + { + return array_reduce($this->cuentas, function(int $sum, $cuenta) { + return $sum + $cuenta->deposito; + }, 0); + } + public function caja(): int + { + return array_reduce($this->cuentas, function(int $sum, $cuenta) { + return $sum + $cuenta->saldo(); + }, 0); + } +} diff --git a/app/src/Service/Contabilidad/Informe/Tesoreria/Output/Data/Totales.php b/app/src/Service/Contabilidad/Informe/Tesoreria/Output/Data/Totales.php new file mode 100644 index 0000000..b59c865 --- /dev/null +++ b/app/src/Service/Contabilidad/Informe/Tesoreria/Output/Data/Totales.php @@ -0,0 +1,36 @@ +actual - $this->anterior; + } + public function saldo(): int + { + return $this->diferencia() + $this->ffmm + $this->deposito; + } + public function cuentas(): int + { + return $this->actual; + } + public function ffmms(): int + { + return $this->ffmm; + } + public function depositos(): int + { + return $this->deposito; + } + public function caja(): int + { + return $this->cuentas() + $this->ffmms() + $this->depositos(); + } +} diff --git a/app/src/Service/Contabilidad/Informe/Tesoreria/Excel.php b/app/src/Service/Contabilidad/Informe/Tesoreria/Output/Excel.php similarity index 99% rename from app/src/Service/Contabilidad/Informe/Tesoreria/Excel.php rename to app/src/Service/Contabilidad/Informe/Tesoreria/Output/Excel.php index fe83b77..d40ea0d 100644 --- a/app/src/Service/Contabilidad/Informe/Tesoreria/Excel.php +++ b/app/src/Service/Contabilidad/Informe/Tesoreria/Output/Excel.php @@ -1,8 +1,8 @@ fillColumns($sheet, $columns, $styles, $startRow); $rowIndex = $startRow + 1; - $sociedades = $data['inmobiliarias']; + $sociedades = $data['sociedades']; foreach ($sociedades as $dataSociedad) { $rowIndex += $this->fillSociedad($sheet, $dataSociedad, $rowIndex); } @@ -461,7 +461,7 @@ class Excel extends Ideal\Service protected function fillSociedad(PhpSpreadsheet\Worksheet\Worksheet $sheet, object $dataSociedad, int $baseRowIndex): int { $rowIndex = $baseRowIndex; - $sheet->getCell("B{$rowIndex}")->setValue($dataSociedad->inmobiliaria->razon); + $sheet->getCell("B{$rowIndex}")->setValue($dataSociedad->sociedad->razon); foreach ($dataSociedad->cuentas as $cuentaRowIndex => $cuenta) { $this->fillCuenta($sheet, $cuenta, 3, $baseRowIndex + $cuentaRowIndex); } diff --git a/app/src/Service/Contabilidad/Informe/Tesoreria/PDF.php b/app/src/Service/Contabilidad/Informe/Tesoreria/Output/PDF.php similarity index 66% rename from app/src/Service/Contabilidad/Informe/Tesoreria/PDF.php rename to app/src/Service/Contabilidad/Informe/Tesoreria/Output/PDF.php index 7357299..2c050e6 100644 --- a/app/src/Service/Contabilidad/Informe/Tesoreria/PDF.php +++ b/app/src/Service/Contabilidad/Informe/Tesoreria/Output/PDF.php @@ -1,5 +1,5 @@ movimientoRepository->fetchAmountBySociedadAndMes($sociedad_rut, $mes, $amount)); } + public function getByCuentaAndFechaAndGlosaAndCargoAndAbonoAndSaldo(int $cuenta_id, DateTimeInterface $fecha, string $glosa, int $cargo, int $abono, int $saldo): Model\Contabilidad\Movimiento + { + return $this->process($this->movimientoRepository->fetchByCuentaAndFechaAndGlosaAndCargoAndAbonoAndSaldo($cuenta_id, $fecha, $glosa, $cargo, $abono, $saldo)); + } + public function add(array $data): Model\Contabilidad\Movimiento + { + try { + $movimiento = $this->movimientoRepository->fetchByCuentaAndFechaAndGlosaAndCargoAndAbonoAndSaldo($data['cuenta_id'], $data['fecha'], $data['glosa'], $data['cargo'] ?? 0, $data['abono'] ?? 0, $data['saldo']); + } catch (Implement\Exception\EmptyResult) { + $data['fecha'] = $data['fecha']->format('Y-m-d'); + $movimiento = $this->movimientoRepository->create($data); + $movimiento = $this->movimientoRepository->save($movimiento); + } + $movimiento = $this->setDetalles($movimiento, $data); + return $this->process($movimiento); + } public function setDetalles(Model\Contabilidad\Movimiento $movimiento, array $data): Model\Contabilidad\Movimiento { try { @@ -48,9 +65,20 @@ class Movimiento extends Service public function process(Model\Contabilidad\Movimiento $movimiento): Model\Contabilidad\Movimiento { - $movimiento->addFactory('detalles', (new Implement\Repository\Factory())->setCallable(function(int $movimiento_id) { - return $this->detalleRepository->fetchByMovimiento($movimiento_id); - })->setArgs(['movimiento_id' => $movimiento->id])); + $movimiento->addFactory('detalles', (new Implement\Repository\Factory()) + ->setCallable(function(int $movimiento_id) { + try { + return $this->detalleRepository->fetchByMovimiento($movimiento_id); + } catch (Implement\Exception\EmptyResult) { + return null; + } + }) + ->setArgs(['movimiento_id' => $movimiento->id])); + /*$movimiento->addFactory('auxiliares', (new Implement\Repository\Factory()) + ->setCallable(function(int $movimiento_id) { + return $this->auxiliarService->getByMovimiento($movimiento_id); + }) + ->setArgs(['movimiento_id' => $movimiento->id]));*/ return $movimiento; } } diff --git a/app/src/Service/Contabilidad/Movimiento/Auxiliar.php b/app/src/Service/Contabilidad/Movimiento/Auxiliar.php new file mode 100644 index 0000000..23fba55 --- /dev/null +++ b/app/src/Service/Contabilidad/Movimiento/Auxiliar.php @@ -0,0 +1,42 @@ +auxiliarRepository->fetchByMovimiento($movimiento_id)); + } catch (Implement\Exception\EmptyResult) { + return null; + } + } + + protected function process(Model\Contabilidad\Movimiento\Auxiliar $auxiliar): Model\Contabilidad\Movimiento\Auxiliar + { + $auxiliar->addFactory('detalles', (new Implement\Repository\Factory()) + ->setCallable(function(int $auxiliar_id) { + try { + return $this->detalleRepository->fetchByAuxiliar($auxiliar_id); + } catch (Implement\Exception\EmptyResult) { + return null; + } + }) + ->setArgs(['auxiliar_id' => $auxiliar->id])); + return $auxiliar; + } +} diff --git a/app/src/Service/Contabilidad/Nubox.php b/app/src/Service/Contabilidad/Nubox.php index 31d18e5..d100e5c 100644 --- a/app/src/Service/Contabilidad/Nubox.php +++ b/app/src/Service/Contabilidad/Nubox.php @@ -40,9 +40,6 @@ class Nubox extends Ideal\Service ->withHeader('Content-Type', 'application/json') ->withHeader('Accept', 'application/json'); $response = $this->client->sendRequest($request); - if ($response->getStatusCode() !== 200) { - throw new Exception\HttpResponse($response->getReasonPhrase(), $response->getStatusCode()); - } $sistemas = json_decode($response->getBody()->getContents(), JSON_OBJECT_AS_ARRAY); $this->setToken($inmobiliaria_rut, $response->getHeaderLine('Token')) @@ -133,9 +130,6 @@ class Nubox extends Ideal\Service ]; $uri = 'contabilidad/libro-mayor?' . http_build_query($query); $response = $this->send($uri, $inmobiliaria_rut); - if ($response->getStatusCode() !== 200) { - throw new Exception\HttpResponse($response->getReasonPhrase(), $response->getStatusCode()); - } return json_decode($response->getBody()->getContents(), JSON_OBJECT_AS_ARRAY); } public function getLibroDiario(int $inmobiliaria_rut, DateTimeInterface $from, DateTimeInterface $to): array @@ -157,10 +151,6 @@ class Nubox extends Ideal\Service ]; $uri = 'contabilidad/libro-diario?' . http_build_query($query); $response = $this->send($uri, $inmobiliaria_rut); - if ($response->getStatusCode() !== 200) { - $this->logger->debug($uri); - throw new Exception\HttpResponse($response->getReasonPhrase(), $response->getStatusCode()); - } return json_decode($response->getBody()->getContents(), JSON_OBJECT_AS_ARRAY); } public function getMesCuenta(int $inmobiliaria_rut, string $cuenta, DateTimeInterface $mes): array @@ -186,11 +176,29 @@ class Nubox extends Ideal\Service ]; $uri = 'contabilidad/libro-mayor?' . http_build_query($query); $response = $this->send($uri, $inmobiliaria_rut); - if ($response->getStatusCode() !== 200) { - throw new Exception\HttpResponse($response->getReasonPhrase(), $response->getStatusCode()); - } return json_decode($response->getBody()->getContents(), JSON_OBJECT_AS_ARRAY); } + public function getFacturas(int $inmobiliaria_rut, DateTimeInterface $dia): array + { + //$inmobiliaria = $this->nuboxRepository->fetchByInmobiliaria($inmobiliaria_rut); + $query = [ + 'factura', + 'documento', + '78017310-6', + 'estadoVenta', + 551, + 'FAC-EL', + 1 + ]; + $uri = implode('/', $query); + $response = $this->send($uri, $inmobiliaria_rut); + $content = json_decode($response->getBody()->getContents(), JSON_OBJECT_AS_ARRAY); + if (!is_array($content)) { + $this->logger->error($content); + return []; + } + return $content; + } private function send(string $uri, int $inmobiliaria_rut, string $method = 'GET', ?StreamInterface $body = null): ResponseInterface { @@ -200,6 +208,12 @@ class Nubox extends Ideal\Service if ($body !== null) { $request = $request->withBody($body); } - return $this->client->sendRequest($request); + $response = $this->client->sendRequest($request); + if ($response->getStatusCode() !== 200) { + $json = json_decode($response->getBody()->getContents(), JSON_OBJECT_AS_ARRAY); + $message = $json['Message'] ?? ''; + throw new Exception\HttpResponse($response->getReasonPhrase(), $message, $response->getStatusCode()); + } + return $response; } } diff --git a/app/src/Service/Persona.php b/app/src/Service/Persona.php new file mode 100644 index 0000000..0330f08 --- /dev/null +++ b/app/src/Service/Persona.php @@ -0,0 +1,56 @@ +process($this->personaRepository->fetchByRut($rut)); + } + public function add(array $data): Model\Persona + { + try { + $persona = $this->personaRepository->fetchByRut($data['rut']); + } catch (Implement\Exception\EmptyResult) { + $persona = $this->personaRepository->create($data); + $persona = $this->personaRepository->save($persona); + } + if (isset($data['email']) or isset($data['telefono'])) { + $datosData = ['persona_rut' => $persona->rut]; + if (isset($data['email'])) { + $datosData['email'] = $data['email']; + } + if (isset($data['telefono'])) { + $datosData['telefono'] = $data['telefono']; + } + try { + $datos = $this->datosPersonaRepository->fetchByPersona($persona->rut); + $this->datosPersonaRepository->edit($datos, $data); + } catch (Implement\Exception\EmptyResult) { + $datos = $this->datosPersonaRepository->create($datosData); + $this->datosPersonaRepository->save($datos); + } + } + return $this->process($persona); + } + + protected function process(Model\Persona $persona): Model\Persona + { + $persona->addFactory('datos', (new Implement\Repository\Factory()) + ->setCallable([$this->datosPersonaRepository, 'fetchByPersona']) + ->setArgs(['persona_rut' => $persona->rut])); + return $persona; + } +} diff --git a/app/src/Service/Sociedad.php b/app/src/Service/Sociedad.php new file mode 100644 index 0000000..c2844bb --- /dev/null +++ b/app/src/Service/Sociedad.php @@ -0,0 +1,85 @@ +process($this->sociedadRepository->fetchById($sociedad_rut)); + } catch (EmptyResult) { + return null; + } + } + public function getAll(?string $orderBy = null): array + { + try { + return array_map([$this, 'process'], $this->sociedadRepository->fetchAll($orderBy)); + } catch (EmptyResult) { + return []; + } + } + public function add(array $data): ?Model\Sociedad + { + try { + return $this->process($this->sociedadRepository->fetchById($data['rut'])); + } catch (EmptyResult) { + try { + return $this->process($this->sociedadRepository->save($this->sociedadRepository->create($data))); + } catch (EmptyResult) { + return null; + } + } + } + public function edit(int $sociedad_rut, array $data): ?Model\Sociedad + { + try { + return $this->process( + $this->sociedadRepository->edit( + $this->sociedadRepository->fetchById($sociedad_rut), $data)); + } catch (EmptyResult) { + return null; + } + } + public function delete(int $sociedad_rut): bool + { + try { + $this->sociedadRepository->remove($this->sociedadRepository->fetchById($sociedad_rut)); + return true; + } catch (EmptyResult) { + return false; + } + } + public function asignar(int $inmobiliaria_rut, int $sociedad_rut): ?Model\Inmobiliaria\Proveedor + { + try { + $inmobiliaria = $this->inmobiliariaRepository->fetchById($inmobiliaria_rut); + $sociedad = $this->sociedadRepository->fetchById($sociedad_rut); + $data = [ + 'inmobiliaria_rut' => $inmobiliaria->rut, + 'sociedad_rut' => $sociedad->rut, + ]; + return $this->proveedorRepository->save($this->proveedorRepository->create($data)); + } catch (EmptyResult) { + return null; + } + } + + protected function process(Model\Sociedad $sociedad): Model\Sociedad + { + return $sociedad; + } +} diff --git a/app/src/Service/Venta/Factura.php b/app/src/Service/Venta/Factura.php new file mode 100644 index 0000000..7715810 --- /dev/null +++ b/app/src/Service/Venta/Factura.php @@ -0,0 +1,95 @@ +facturaRepository->fetchAll($orderBy)); + } catch (Implement\Exception\EmptyResult) { + return []; + } + } + public function getByVenta(int $venta_id): array + { + try { + return array_map([$this, 'process'], $this->facturaRepository->fetchByVenta($venta_id)); + } catch (Implement\Exception\EmptyResult) { + return []; + } + } + public function getById(int $factura_id): ?Model\Venta\Factura + { + try { + return $this->process($this->facturaRepository->fetchById($factura_id)); + } catch (Implement\Exception\EmptyResult) { + return null; + } + } + public function getByVentaAndIndex(int $venta_id, int $index): ?Model\Venta\Factura + { + try { + return $this->process($this->facturaRepository->fetchByVentaAndIndex($venta_id, $index)); + } catch (Implement\Exception\EmptyResult) { + return null; + } + } + + public function add(array $data): Model\Venta\Factura + { + $factura = $this->getByVentaAndIndex($data['venta_id'], $data['index']); + if ($factura !== null) { + return $factura; + } + $factura = $this->facturaRepository->save($this->facturaRepository->create($data)); + $tipo = $this->tipoRepository->fetchByDescripcion('generada'); + $this->estadoRepository->save($this->estadoRepository->create([ + 'factura_id' => $factura->id, + 'tipo_id' => $tipo->id, + 'fecha' => $factura->fecha + ])); + return $this->process($factura); + } + public function aprobar(int $factura_id, DateTimeInterface $fecha): ?Model\Venta\Factura + { + try { + $factura = $this->facturaRepository->fetchById($factura_id); + $tipo = $this->tipoRepository->fetchByDescripcion('aprobada'); + $this->estadoRepository->save($this->estadoRepository->create([ + 'factura_id' => $factura->id, + 'tipo_id' => $tipo->id, + 'fecha' => $fecha->format('Y-m-d') + ])); + return $this->process($factura); + } catch (Implement\Exception\EmptyResult) { + $this->logger->error('Error al aprobar factura', ['factura_id' => $factura_id]); + return null; + } + } + + protected function process(Model\Venta\Factura $factura): Model\Venta\Factura + { + $factura->addFactory('estados', (new Implement\Repository\Factory()) + ->setCallable(function($factura_id) { + return $this->estadoRepository->fetchByFactura($factura_id); + }) + ->setArgs(['factura_id' => $factura->id])); + return $factura; + } +} diff --git a/app/src/Service/Venta/Propietario.php b/app/src/Service/Venta/Propietario.php index 0882104..a0de35a 100644 --- a/app/src/Service/Venta/Propietario.php +++ b/app/src/Service/Venta/Propietario.php @@ -94,7 +94,7 @@ class Propietario extends Service if ($sociedad->datos->direccion->id !== $mapped_data['direccion']) { $edits['direccion'] = $mapped_data['direccion']; } - if ($sociedad->representante->rut !== $mapped_data['representante']) { + if ($sociedad->contacto->rut !== $mapped_data['representante']) { $edits['representante'] = $mapped_data['representante']; } $sociedad = $this->propietarioRepository->edit($sociedad, $edits); diff --git a/php-memory.ini b/php-memory.ini new file mode 100644 index 0000000..50601e5 --- /dev/null +++ b/php-memory.ini @@ -0,0 +1,2 @@ +memory_limit = 512M +max_execution_time = 300 diff --git a/php.ini.bak b/php.ini.bak new file mode 100644 index 0000000..b3d2738 Binary files /dev/null and b/php.ini.bak differ diff --git a/redisinsight.compose.yml b/redisinsight.compose.yml new file mode 100644 index 0000000..b813053 --- /dev/null +++ b/redisinsight.compose.yml @@ -0,0 +1,14 @@ +services: + insight: + profiles: + - insight + container_name: incoviba_insight + image: redis/redisinsight:latest + restart: unless-stopped + volumes: + - redisinsight:/data + ports: + - "5540:5540" + +volumes: + redisinsight: {}