From 7578775fed3aecb101fad73cee68ca7445c94a02 Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Thu, 16 Jan 2025 19:33:21 -0300 Subject: [PATCH 01/14] Migraciones --- .../20141101080037_create_factura_venta.php | 22 ----------------- ...1101080037_create_venta_datos_facturas.php | 24 +++++++++++++++++++ .../20141101080038_create_facturas.php | 9 +++---- 3 files changed, 29 insertions(+), 26 deletions(-) delete mode 100644 app/resources/database/migrations/20141101080037_create_factura_venta.php create mode 100644 app/resources/database/migrations/20141101080037_create_venta_datos_facturas.php diff --git a/app/resources/database/migrations/20141101080037_create_factura_venta.php b/app/resources/database/migrations/20141101080037_create_factura_venta.php deleted file mode 100644 index 1556250..0000000 --- a/app/resources/database/migrations/20141101080037_create_factura_venta.php +++ /dev/null @@ -1,22 +0,0 @@ -execute('SET unique_checks=0; SET foreign_key_checks=0;'); - $this->execute("ALTER DATABASE CHARACTER SET 'utf8mb4';"); - $this->execute("ALTER DATABASE COLLATE='utf8mb4_general_ci';"); - - $this->table('factura_venta') - ->addColumn('factura_id', 'integer', ['length' => 10, 'null' => false, 'signed' => false]) - ->addColumn('venta_id', 'integer', ['length' => 10, 'null' => false, 'signed' => false]) - ->addColumn('valor', 'double', ['null' => false]) - ->addForeignKey('factura_id', 'factura_proyecto_operador', 'id', ['delete' => 'cascade', 'update' => 'cascade']) - ->addForeignKey('venta_id', 'venta', 'id', ['delete' => 'cascade', 'update' => 'cascade']) - ->create(); - $this->execute('SET unique_checks=1; SET foreign_key_checks=1;'); - } -} diff --git a/app/resources/database/migrations/20141101080037_create_venta_datos_facturas.php b/app/resources/database/migrations/20141101080037_create_venta_datos_facturas.php new file mode 100644 index 0000000..cea37ba --- /dev/null +++ b/app/resources/database/migrations/20141101080037_create_venta_datos_facturas.php @@ -0,0 +1,24 @@ +execute('SET unique_checks=0; SET foreign_key_checks=0;'); + $this->execute("ALTER DATABASE CHARACTER SET 'utf8mb4';"); + $this->execute("ALTER DATABASE COLLATE='utf8mb4_general_ci';"); + + $this->table('venta_datos_facturas') + ->addColumn('venta_id', 'integer', ['length' => 10, 'signed' => false]) + ->addColumn('fecha', 'date') + ->addColumn('uf', 'string', ['length' => 50]) // fecha, valor + ->addColumn('ipc', 'string', ['length' => 50]) // fecha, valor + ->addColumn('terreno', 'integer', ['signed' => false]) + ->addColumn('unidades', 'text') // id, precios, prorrateo + ->addForeignKey('venta_id', 'venta', 'id', ['delete' => 'cascade', 'update' => 'cascade']) + ->create(); + $this->execute('SET unique_checks=1; SET foreign_key_checks=1;'); + } +} diff --git a/app/resources/database/migrations/20141101080038_create_facturas.php b/app/resources/database/migrations/20141101080038_create_facturas.php index 0cd4c00..3938e9b 100644 --- a/app/resources/database/migrations/20141101080038_create_facturas.php +++ b/app/resources/database/migrations/20141101080038_create_facturas.php @@ -11,11 +11,12 @@ class CreateFacturas extends Phinx\Migration\AbstractMigration $this->execute("ALTER DATABASE COLLATE='utf8mb4_general_ci';"); $this->table('facturas') - ->addColumn('venta_id', 'integer', ['length' => 10, 'null' => false, 'signed' => false]) - ->addColumn('index', 'integer', ['length' => 10, 'null' => false, 'signed' => false]) - ->addColumn('proporcion', 'double', ['null' => false, 'signed' => false]) - ->addColumn('data', 'text', ['null' => false]) + ->addColumn('venta_id', 'integer', ['length' => 10, 'signed' => false]) + ->addColumn('index', 'integer', ['signed' => false]) + ->addColumn('proporcion', 'double', ['signed' => false]) // % + ->addColumn('cliente_rut', 'integer', ['length' => 10, 'signed' => false]) ->addForeignKey('venta_id', 'venta', 'id', ['delete' => 'cascade', 'update' => 'cascade']) + ->addForeignKey('cliente_rut', 'personas', 'rut', ['delete' => 'cascade', 'update' => 'cascade']) ->create(); $this->execute('SET unique_checks=1; SET foreign_key_checks=1;'); } -- 2.49.0 From 5f31bff6e5b8e8e7683cfbc91b2b041eba3d92b1 Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Thu, 16 Jan 2025 19:36:28 -0300 Subject: [PATCH 02/14] Nueva estructura --- app/src/Model/Venta/Factura.php | 112 ++++++++++-------- app/src/Repository/Venta/Factura.php | 171 +++++++++++++++++---------- 2 files changed, 172 insertions(+), 111 deletions(-) diff --git a/app/src/Model/Venta/Factura.php b/app/src/Model/Venta/Factura.php index cb0b259..e1058c0 100644 --- a/app/src/Model/Venta/Factura.php +++ b/app/src/Model/Venta/Factura.php @@ -8,30 +8,16 @@ use Incoviba\Model; class Factura extends Ideal\Model { public Model\Venta $venta; + public int $index; public float $proporcion; - public string $emisorRut; - public string $emisorNombre; - public string $emisorDireccion; - public string $receptorRut; - public string $receptorNombre; - public string $receptorDireccion; - public string $receptorComuna; + public Model\Persona $cliente; + public DateTimeInterface $fecha; - public array $unidades; - public int $detalleBase; - public int $detalleTerreno; - public int $detalleNeto; - public int $detalleIva; - public int $detalleBruto; - public float $detalleDescuento; - public int $detalleTotal; - public int $totalNeto; - public int $totalExento; - public int $totalIva; - public int $totalTotal; - public DateTimeInterface $fechaUF; - public float $valorUF; + public array $unidades; // [[unidad, descripcion, precio, prorrateo]] + public int $terreno; + public object $uf; // [fecha, valor] + public object $ipc; // [fecha, valor] protected array $estados; public function estados(): array @@ -42,6 +28,52 @@ class Factura extends Ideal\Model return $this->estados ?? []; } + public function total(): int + { + return round($this->venta->valor * $this->uf->valor * $this->proporcion); + } + public function bruto(): int + { + return round($this->total() - $this->terreno * $this->proporcion); + } + public function iva(): int + { + return round($this->bruto() / 1.19 * .19); + } + public function neto(): int + { + return round($this->bruto() / 1.19); + } + public function base(): int + { + return $this->neto() + $this->terreno * $this->proporcion; + } + public function detalle(): array + { + return [ + 'base' => $this->base(), + 'terreno' => $this->terreno * $this->proporcion, + 'neto' => $this->neto(), + 'iva' => $this->iva(), + 'bruto' => $this->bruto(), + 'total' => $this->total(), + 'descuento' => array_reduce($this->unidades, function($sum, $unidad) { + return $sum + $unidad->prorrateo * $this->proporcion; + }) + ]; + } + public function totales(): array + { + return [ + 'neto' => array_reduce($this->unidades, function($sum, $unidad) { + return $sum + $unidad->precio * $this->proporcion; + }), + 'exento' => $this->terreno * $this->proporcion, + 'iva' => $this->iva(), + 'total' => $this->total() + ]; + } + public function jsonSerialize(): mixed { return array_merge(parent::jsonSerialize(), [ @@ -49,37 +81,23 @@ class Factura extends Ideal\Model 'index' => $this->index, 'proporcion' => $this->proporcion, 'emisor' => [ - 'rut' => $this->emisorRut, - 'nombre' => $this->emisorNombre, - 'direccion' => $this->emisorDireccion + 'rut' => $this->venta->proyecto()->inmobiliaria()->rut(), + 'nombre' => $this->venta->proyecto()->inmobiliaria()->nombreCompleto(), + 'direccion' => $this->venta->proyecto()->direccion(), + 'comuna' => $this->venta->proyecto()->direccion()->comuna->descripcion ], 'receptor' => [ - 'rut' => $this->receptorRut, - 'nombre' => $this->receptorNombre, - 'direccion' => $this->receptorDireccion, - 'comuna' => $this->receptorComuna + 'rut' => $this->cliente->rutCompleto(), + 'nombre' => $this->cliente->nombreCompleto(), + 'direccion' => $this->cliente->datos()->direccion->simple(), + 'comuna' => $this->cliente->datos()->direccion->comuna->descripcion ], '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 - ], + 'detalle' => $this->detalle(), + 'total' => $this->totales(), + 'uf' => $this->uf, + 'ipc' => $this->ipc, 'estados' => $this->estados() ]); } diff --git a/app/src/Repository/Venta/Factura.php b/app/src/Repository/Venta/Factura.php index 0bd8716..8b529ec 100644 --- a/app/src/Repository/Venta/Factura.php +++ b/app/src/Repository/Venta/Factura.php @@ -1,6 +1,7 @@ setTable('facturas'); @@ -19,89 +21,130 @@ class Factura extends Ideal\Repository public function create(?array $data = null): Model\Venta\Factura { - $map = (new Implement\Repository\MapperParser(['index'])) + $map = (new Implement\Repository\MapperParser(['index', 'proporcion'])) ->register('venta_id', (new Implement\Repository\Mapper()) ->setProperty('venta') ->setFunction(function($data) { return $this->ventaRepository->fetchById($data['venta_id']); + })) + ->register('cliente_rut', (new Implement\Repository\Mapper()) + ->setProperty('cliente') + ->setFunction(function($data) { + return $this->personaRepository->fetchById($data['cliente_rut']); })); $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 $this->createDatos($factura); + } + public function createDatos(Model\Venta\Factura &$factura): Model\Venta\Factura + { + try { + $result = $this->getDatos($factura->venta->id); + $factura->fecha = new DateTimeImmutable($result['fecha']); + $factura->unidades = array_map(function($datos) { + $unidad = $this->unidadRepository->fetchById($datos->unidad_id); + return (object) [ + 'unidad' => $unidad, + 'descripcion' => implode(' ', [ucwords($unidad->proyectoTipoUnidad->tipoUnidad->descripcion), $unidad->descripcion]), + 'precio' => $datos->precio, + 'prorrateo' => $datos->prorrateo + ]; + }, json_decode($result['unidades'])); + $factura->terreno = $result['terreno']; + $factura->uf = json_decode($result['uf']); + $factura->ipc = json_decode($result['ipc']); + } catch (EmptyResult) {} + return $factura; } + protected function getDatos(int $venta_id): array + { + $query = $this->connection->getQueryBuilder() + ->select() + ->from('venta_datos_facturas') + ->where('venta_id = :venta_id'); + $result = $this->connection->execute($query, ['venta_id' => $venta_id])->fetch(PDO::FETCH_ASSOC); + if ($result === false) { + throw new EmptyResult($query); + } + return $result; + } public function save(Define\Model $model): Model\Venta\Factura { $model->id = $this->saveNew([ 'venta_id', 'index', - 'data' + 'proporcion', + 'cliente_rut' ], [ $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 - ] - ]) + $model->proporcion, + $model->cliente->rut ]); - return $model; + return $this->saveDatos($model); + } + protected function saveDatos(Model\Venta\Factura $factura): Model\Venta\Factura + { + try { + $this->getDatos($factura->venta->id); + } catch (EmptyResult) { + $query = $this->connection->getQueryBuilder() + ->insert() + ->into('venta_datos_facturas') + ->values([ + 'venta_id' => $factura->venta->id, + 'index' => $factura->index, + 'proporcion' => $factura->proporcion, + 'unidades' => json_encode(array_map(function($unidad) { + return [ + 'unidad_id' => $unidad->unidad->id, + 'precio' => $unidad->precio, + 'prorrateo' => $unidad->prorrateo + ]; + }, $factura->unidades)), + 'terreno' => $factura->terreno, + 'uf' => json_encode($factura->uf), + 'ipc' => json_encode($factura->ipc) + ]); + $this->connection->execute($query); + } + + return $factura; } public function edit(Define\Model $model, array $new_data): Model\Venta\Factura { - return $this->update($model, ['venta_id', 'index', 'data'], $new_data); + $model = $this->editDatos($model, $new_data); + return $this->update($model, ['venta_id', 'index', 'proporcion', 'cliente_rut'], $new_data); + } + protected function editDatos(Model\Venta\Factura $factura, array $new_data): Model\Venta\Factura + { + $dataFields = [ + 'fecha', + 'unidades', + 'terreno', + 'uf', + 'ipc' + ]; + $fields = []; + $values = []; + foreach ($dataFields as $field) { + if (isset($new_data[$field])) { + $fields[] = "{$field} = ?"; + $values[] = is_array($new_data[$field]) ? json_encode($new_data[$field]) : $new_data[$field]; + } + } + if (count($fields) === 0) { + return $factura; + } + + $query = $this->connection->getQueryBuilder() + ->update('venta_datos_facturas') + ->set($fields) + ->where('venta_id = ?') + ->limit(1); + $this->connection->execute($query, array_merge($values, [$factura->venta->id])); + + return $this->fetchById($factura->id); } /** -- 2.49.0 From 16100f622e9ed6ee2830223a56cc7dea7305d5e2 Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Fri, 17 Jan 2025 00:04:11 -0300 Subject: [PATCH 03/14] Se agrega $statusCode --- app/src/Controller/API/withJson.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/Controller/API/withJson.php b/app/src/Controller/API/withJson.php index 1a6e2f4..cc4c051 100644 --- a/app/src/Controller/API/withJson.php +++ b/app/src/Controller/API/withJson.php @@ -5,9 +5,9 @@ use Psr\Http\Message\ResponseInterface; trait withJson { - public function withJson(ResponseInterface $response, array|object $data = []): ResponseInterface + public function withJson(ResponseInterface $response, array|object $data = [], int $statusCode = 200): ResponseInterface { $response->getBody()->write(json_encode($data)); - return $response->withHeader('Content-Type', 'application/json'); + return $response->withStatus($statusCode)->withHeader('Content-Type', 'application/json'); } } -- 2.49.0 From bf054c22c2d555946179570e20c64fda9b742fc3 Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Fri, 17 Jan 2025 00:04:34 -0300 Subject: [PATCH 04/14] Usar success --- app/src/Controller/API/Ventas/Facturas.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/Controller/API/Ventas/Facturas.php b/app/src/Controller/API/Ventas/Facturas.php index 19c4ff2..497914b 100644 --- a/app/src/Controller/API/Ventas/Facturas.php +++ b/app/src/Controller/API/Ventas/Facturas.php @@ -18,11 +18,11 @@ class Facturas extends Controller $output = [ 'input' => $data, 'factura' => null, - 'saved' => false + 'success' => false ]; try { $output['factura'] = $facturaService->add($data); - $output['saved'] = true; + $output['success'] = true; } catch (Implement\Exception\EmptyResult) { $output['error'] = 'No se pudo agregar la factura'; return $this->withJson($response, $output, 400); -- 2.49.0 From 45e9487b5c01c97f56ae24e7bc18e626486baac2 Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Fri, 17 Jan 2025 00:04:55 -0300 Subject: [PATCH 05/14] Dropdown de Comunas --- app/src/Controller/Ventas/Facturacion.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/Controller/Ventas/Facturacion.php b/app/src/Controller/Ventas/Facturacion.php index 39ccccb..1563277 100644 --- a/app/src/Controller/Ventas/Facturacion.php +++ b/app/src/Controller/Ventas/Facturacion.php @@ -8,6 +8,7 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Incoviba\Common\Alias\View; use Incoviba\Common\Ideal; +use Incoviba\Repository; use Incoviba\Service; class Facturacion extends Ideal\Controller @@ -29,6 +30,7 @@ class Facturacion extends Ideal\Controller Service\Venta $ventaService, Service\Proyecto\Terreno $terrenoService, Service\IPC $ipcService, Service\UF $ufService, Service\Venta\Factura $facturasService, + Repository\Comuna $comunaRepository, int $venta_id): ResponseInterface { $venta = $ventaService->getById($venta_id); @@ -48,7 +50,8 @@ class Facturacion extends Ideal\Controller } } $facturas = $facturasService->getByVenta($venta->id); + $comunas = $comunaRepository->fetchAll('descripcion'); - return $view->render($response, 'ventas.facturacion.show', compact('venta', 'terreno', 'uf', 'ipc', 'facturas')); + return $view->render($response, 'ventas.facturacion.show', compact('venta', 'terreno', 'uf', 'ipc', 'facturas', 'comunas')); } } -- 2.49.0 From 055bf6ab2025642b4f51fa5abe3433e38f6a5d13 Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Fri, 17 Jan 2025 00:06:02 -0300 Subject: [PATCH 06/14] Cambios en formato --- app/src/Model/Venta/Factura.php | 17 ++++++++++------- app/src/Repository/Venta/Factura.php | 8 +++++--- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/app/src/Model/Venta/Factura.php b/app/src/Model/Venta/Factura.php index e1058c0..f3d4d1b 100644 --- a/app/src/Model/Venta/Factura.php +++ b/app/src/Model/Venta/Factura.php @@ -30,19 +30,19 @@ class Factura extends Ideal\Model public function total(): int { - return round($this->venta->valor * $this->uf->valor * $this->proporcion); + return $this->venta->valor * $this->uf->valor * $this->proporcion; } public function bruto(): int { - return round($this->total() - $this->terreno * $this->proporcion); + return $this->total() - $this->terreno * $this->proporcion; } public function iva(): int { - return round($this->bruto() / 1.19 * .19); + return $this->neto() * .19; } public function neto(): int { - return round($this->bruto() / 1.19); + return $this->bruto() / 1.19; } public function base(): int { @@ -83,7 +83,7 @@ class Factura extends Ideal\Model 'emisor' => [ 'rut' => $this->venta->proyecto()->inmobiliaria()->rut(), 'nombre' => $this->venta->proyecto()->inmobiliaria()->nombreCompleto(), - 'direccion' => $this->venta->proyecto()->direccion(), + 'direccion' => $this->venta->proyecto()->direccion()->simple(), 'comuna' => $this->venta->proyecto()->direccion()->comuna->descripcion ], 'receptor' => [ @@ -96,9 +96,12 @@ class Factura extends Ideal\Model 'unidades' => $this->unidades, 'detalle' => $this->detalle(), 'total' => $this->totales(), - 'uf' => $this->uf, - 'ipc' => $this->ipc, + 'uf' => [ + 'fecha' => $this->uf->fecha->format('Y-m-d'), + 'valor' => $this->uf->valor + ], 'estados' => $this->estados() ]); } + } diff --git a/app/src/Repository/Venta/Factura.php b/app/src/Repository/Venta/Factura.php index 8b529ec..abad304 100644 --- a/app/src/Repository/Venta/Factura.php +++ b/app/src/Repository/Venta/Factura.php @@ -40,7 +40,11 @@ class Factura extends Ideal\Repository try { $result = $this->getDatos($factura->venta->id); $factura->fecha = new DateTimeImmutable($result['fecha']); - $factura->unidades = array_map(function($datos) { + $factura->uf = json_decode($result['uf']); + $factura->uf->fecha = new DateTimeImmutable($factura->uf->fecha); + $factura->ipc = json_decode($result['ipc']); + $factura->ipc->fecha = new DateTimeImmutable($factura->ipc->fecha); + $factura->unidades = array_map(function($datos) use ($factura) { $unidad = $this->unidadRepository->fetchById($datos->unidad_id); return (object) [ 'unidad' => $unidad, @@ -50,8 +54,6 @@ class Factura extends Ideal\Repository ]; }, json_decode($result['unidades'])); $factura->terreno = $result['terreno']; - $factura->uf = json_decode($result['uf']); - $factura->ipc = json_decode($result['ipc']); } catch (EmptyResult) {} return $factura; -- 2.49.0 From d74beb55181195111f32dc8cd080fa2dbded2694 Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Fri, 17 Jan 2025 00:07:45 -0300 Subject: [PATCH 07/14] Separacion de objetos --- .../views/ventas/facturacion/show.blade.php | 1050 +---------------- .../ventas/facturacion/show/factura.blade.php | 388 ++++++ .../facturacion/show/propietario.blade.php | 189 +++ .../ventas/facturacion/show/unidad.blade.php | 125 ++ .../ventas/facturacion/show/venta.blade.php | 474 ++++++++ 5 files changed, 1199 insertions(+), 1027 deletions(-) create mode 100644 app/resources/views/ventas/facturacion/show/factura.blade.php create mode 100644 app/resources/views/ventas/facturacion/show/propietario.blade.php create mode 100644 app/resources/views/ventas/facturacion/show/unidad.blade.php create mode 100644 app/resources/views/ventas/facturacion/show/venta.blade.php diff --git a/app/resources/views/ventas/facturacion/show.blade.php b/app/resources/views/ventas/facturacion/show.blade.php index b2146d9..0e8b62a 100644 --- a/app/resources/views/ventas/facturacion/show.blade.php +++ b/app/resources/views/ventas/facturacion/show.blade.php @@ -19,1015 +19,11 @@ @endsection @push('page_scripts') + @include('ventas.facturacion.show.factura') + @include('ventas.facturacion.show.propietario') + @include('ventas.facturacion.show.unidad') + @include('ventas.facturacion.show.venta') diff --git a/app/resources/views/ventas/facturacion/show/propietario.blade.php b/app/resources/views/ventas/facturacion/show/propietario.blade.php new file mode 100644 index 0000000..ce77ebb --- /dev/null +++ b/app/resources/views/ventas/facturacion/show/propietario.blade.php @@ -0,0 +1,189 @@ + diff --git a/app/resources/views/ventas/facturacion/show/unidad.blade.php b/app/resources/views/ventas/facturacion/show/unidad.blade.php new file mode 100644 index 0000000..c290796 --- /dev/null +++ b/app/resources/views/ventas/facturacion/show/unidad.blade.php @@ -0,0 +1,125 @@ + diff --git a/app/resources/views/ventas/facturacion/show/venta.blade.php b/app/resources/views/ventas/facturacion/show/venta.blade.php new file mode 100644 index 0000000..c69a5f8 --- /dev/null +++ b/app/resources/views/ventas/facturacion/show/venta.blade.php @@ -0,0 +1,474 @@ + -- 2.49.0 From e031fd22d31bf9052ee70c53f41a37e3f039b740 Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Fri, 17 Jan 2025 16:55:34 -0300 Subject: [PATCH 08/14] Separacion de objetos --- .../views/ventas/facturacion/show.blade.php | 6 +++-- .../ventas/facturacion/show/factura.blade.php | 26 +++++++++---------- .../facturacion/show/propietario.blade.php | 10 +++---- .../ventas/facturacion/show/venta.blade.php | 25 +++++++----------- 4 files changed, 31 insertions(+), 36 deletions(-) diff --git a/app/resources/views/ventas/facturacion/show.blade.php b/app/resources/views/ventas/facturacion/show.blade.php index 0e8b62a..7b68876 100644 --- a/app/resources/views/ventas/facturacion/show.blade.php +++ b/app/resources/views/ventas/facturacion/show.blade.php @@ -115,7 +115,7 @@ }) @endforeach @else - this.venta.add().propietario({ + const propietario = this.venta.add().propietario({ proporcion: 1, rut: '{{$venta->propietario()->rut()}}', nombre: '{{$venta->propietario()->nombreCompleto()}}', @@ -124,7 +124,9 @@ }) @endif this.draw().venta() - this.venta.update().facturas() + if (typeof propietario !== 'undefined') { + this.venta.add().factura(propietario) + } this.draw().facturas() } } diff --git a/app/resources/views/ventas/facturacion/show/factura.blade.php b/app/resources/views/ventas/facturacion/show/factura.blade.php index 91fa475..1e3af6e 100644 --- a/app/resources/views/ventas/facturacion/show/factura.blade.php +++ b/app/resources/views/ventas/facturacion/show/factura.blade.php @@ -186,16 +186,16 @@ return unidadesData.join("\n") }, unidad: ({unidad, no, classes, formatters}) => { - const descuento = Math.round(this.props.detalle.terreno * unidad.prorrateo) + const descuento = this.props.detalle.terreno * unidad.prorrateo const bruto = unidad.precio - descuento const neto = bruto / 1.19 const data = [ no, unidad.descripcion, '1 UNID', - formatters.pesos.format(neto * this.props.proporcion), + formatters.pesos.format(neto), 'AF', - formatters.pesos.format(neto * this.props.proporcion) + formatters.pesos.format(neto) ] const row = [''] @@ -308,22 +308,24 @@ } } save() { - let url = '{{$urls->api}}/venta/{{$venta->id}}/facturas/add' + let url = '{{$urls->api}}/ventas/facturas/add' if (this.saved) { - url = `{{$urls->api}}/venta/{{$venta->id}}/facturas/${this.props.id}/edit` + url = `{{$urls->api}}/ventas/facturas/${this.props.id}/edit` } const method = 'post' const body = new FormData() - body.set('venta_id', this.props.venta_id) + body.set('venta_id', this.props.venta.id) body.set('index', this.props.index) body.set('proporcion', this.props.proporcion) body.set('cliente', JSON.stringify(this.props.receptor)) - body.set('terreno', this.props.terreno) - body.set('unidades', JSON.stringify(this.props.unidades)) + body.set('terreno', this.props.detalle.terreno) + body.set('unidades', JSON.stringify(this.props.unidades.map(unidad => { + return {unidad_id: unidad.unidad.props.id, precio: unidad.precio, prorrateo: unidad.prorrateo} + }))) body.set('fecha', [this.props.fecha.getFullYear(), this.props.fecha.getMonth()+1, this.props.fecha.getDate()].join('-')) body.set('detalle', JSON.stringify(this.props.detalle)) body.set('total', JSON.stringify(this.props.total)) - body.set('uf', JSON.stringify(this.props.uf)) + body.set('uf', JSON.stringify({fecha: [this.props.uf.fecha.getFullYear(), this.props.uf.fecha.getMonth()+1, this.props.uf.fecha.getDate()].join('-'), valor: this.props.uf.valor})) return APIClient.fetch(url, {method, body}).then(response => { if (!response) { return @@ -345,10 +347,11 @@ this.props.uf.valor = venta.props.uf.valor this.update().propietario(venta.props.propietarios.find(propietario => propietario.props.index === this.props.index)) this.update().unidades(venta.props.unidades) - this.props.detalle.total = venta.props.valor * this.props.proporcion * venta.props.uf.valor + this.props.total.total = this.props.detalle.total = venta.props.valor * this.props.proporcion * venta.props.uf.valor this.update().detalle(venta.props.facturas.terreno.valor * venta.prorrateo) this.props.total.exento = this.props.detalle.terreno this.props.total.iva = this.props.detalle.iva + this.props.total.neto = this.props.unidades.reduce((sum, unidad) => sum + unidad.precio, 0) this.props.detalle.descuento = venta.prorrateo * this.props.proporcion }, detalle: terreno => { @@ -360,7 +363,6 @@ }, unidades: unidades => { this.props.unidades = [] - let neto = 0 unidades.forEach(unidad => { this.props.unidades.push({ unidad: unidad, @@ -368,9 +370,7 @@ precio: unidad.props.valor * this.props.uf.valor * this.props.proporcion, prorrateo: unidad.props.prorrateo * this.props.proporcion }) - neto += unidad.props.valor }) - this.props.total.neto = neto }, propietario: propietario => { this.props.proporcion = propietario.props.proporcion diff --git a/app/resources/views/ventas/facturacion/show/propietario.blade.php b/app/resources/views/ventas/facturacion/show/propietario.blade.php index ce77ebb..f33fe56 100644 --- a/app/resources/views/ventas/facturacion/show/propietario.blade.php +++ b/app/resources/views/ventas/facturacion/show/propietario.blade.php @@ -20,27 +20,27 @@ return { proporcion: (valor) => { this.props.proporcion = valor - facturas.venta.update().totalPropietarios() + facturas.venta.update().facturas() facturas.draw().facturas() }, rut: rut => { this.props.rut = rut - facturas.venta.update().totalPropietarios() + facturas.venta.update().facturas() facturas.draw().facturas() }, nombre: nombre => { this.props.nombre = nombre - facturas.venta.update().totalPropietarios() + facturas.venta.update().facturas() facturas.draw().facturas() }, direccion: direccion => { this.props.direccion = direccion - facturas.venta.update().totalPropietarios() + facturas.venta.update().facturas() facturas.draw().facturas() }, comuna: comuna => { this.props.comuna = comuna - facturas.venta.update().totalPropietarios() + facturas.venta.update().facturas() facturas.draw().facturas() }, } diff --git a/app/resources/views/ventas/facturacion/show/venta.blade.php b/app/resources/views/ventas/facturacion/show/venta.blade.php index c69a5f8..bfb8f4a 100644 --- a/app/resources/views/ventas/facturacion/show/venta.blade.php +++ b/app/resources/views/ventas/facturacion/show/venta.blade.php @@ -59,16 +59,20 @@ p -= this.props.propietarios[index].props.proporcion }) p /= diff + const propietarios = [] for (let i = 0; i < diff; i ++) { - this.add().propietario({ + propietarios.push(this.add().propietario({ rut: '', nombre: '', proporcion: (p*100).toFixed(0)/100, direccion: '', comuna: '' - }) + })) } document.getElementById('propietarios').innerHTML = this.draw().propietarios() + propietarios.forEach(propietario => { + this.add().factura(propietario) + }) this.watch().propietarios() this.update().facturas() return @@ -121,16 +125,7 @@ '') $total.find('.ui.message').css('display', 'inline-block') - this.props.facturas.forEach(factura => { - factura.update().unidades(this.props.unidades) - }) - }, - totalPropietarios: () => { - this.props.propietarios.forEach(propietario => { - const index = propietario.props.index - const factura = this.props.facturas.facturas.find(factura => factura.props.index === index) - factura.update().venta(this) - }) + this.update().facturas() }, terreno: newValue => { const date = this.props.last.november @@ -250,7 +245,6 @@ return } this.update().propietarios(count) - this.update().totalPropietarios() facturas.draw().facturas() }) }, @@ -396,7 +390,6 @@ const index = this.props.propietarios.length + 1 const propietario = new Propietario({index, proporcion, rut, nombre, direccion, comuna}) this.props.propietarios.push(propietario) - this.add().factura(propietario) return propietario }, factura: propietario => { @@ -455,7 +448,7 @@ this.remove().factura(index) }, factura: index => { - this.props.facturas.splice(index, 1) + this.props.facturas.facturas.splice(index, 1) document.getElementById('facturas').querySelectorAll("[data-index='"+(index+1)+"']").forEach(factura => { factura.remove() }) @@ -465,7 +458,7 @@ save() { return { factura: ({index}) => { - const factura = this.props.facturas[index] + const factura = this.props.facturas.facturas[index] return factura.save() } } -- 2.49.0 From a5572e7c6ac8fdd0682e65ed29f27095f4ef5e7a Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Fri, 17 Jan 2025 16:55:46 -0300 Subject: [PATCH 09/14] Ruta para editar --- app/resources/routes/api/ventas/facturas.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/resources/routes/api/ventas/facturas.php b/app/resources/routes/api/ventas/facturas.php index 697f1b0..fb97561 100644 --- a/app/resources/routes/api/ventas/facturas.php +++ b/app/resources/routes/api/ventas/facturas.php @@ -4,3 +4,6 @@ use Incoviba\Controller\API\Ventas\Facturas; $app->group('/facturas', function($app) { $app->post('/add[/]', [Facturas::class, 'add']); }); +$app->group('/facturas/{factura_id}', function($app) { + $app->post('/edit[/]', [Facturas::class, 'edit']); +}); -- 2.49.0 From 079fd3bc741db8ac08a035f18906c855abdcd036 Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Fri, 17 Jan 2025 16:56:03 -0300 Subject: [PATCH 10/14] Mapeo de JSONs --- app/src/Controller/API/Ventas/Facturas.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/Controller/API/Ventas/Facturas.php b/app/src/Controller/API/Ventas/Facturas.php index 497914b..8757bcd 100644 --- a/app/src/Controller/API/Ventas/Facturas.php +++ b/app/src/Controller/API/Ventas/Facturas.php @@ -21,6 +21,12 @@ class Facturas extends Controller 'success' => false ]; try { + foreach (['cliente', 'unidades', 'detalle', 'total', 'uf'] as $key) { + if (!isset($data[$key]) or empty($data[$key])) { + continue; + } + $data[$key] = json_decode($data[$key], true); + } $output['factura'] = $facturaService->add($data); $output['success'] = true; } catch (Implement\Exception\EmptyResult) { -- 2.49.0 From ef465580408ad7ef05201bed69870760aebf0828 Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Fri, 17 Jan 2025 16:56:13 -0300 Subject: [PATCH 11/14] Fix de index --- app/src/Repository/Venta/Factura.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/Repository/Venta/Factura.php b/app/src/Repository/Venta/Factura.php index abad304..97ee81c 100644 --- a/app/src/Repository/Venta/Factura.php +++ b/app/src/Repository/Venta/Factura.php @@ -168,7 +168,7 @@ class Factura extends Ideal\Repository $query = $this->connection->getQueryBuilder() ->select() ->from($this->getTable()) - ->where('venta_id = :venta_id AND index = :index'); + ->where('venta_id = :venta_id AND `index` = :index'); return $this->fetchOne($query, ['venta_id' => $venta_id, 'index' => $index]); } } -- 2.49.0 From 5f31b6857e6128e277b86c6aaa076ed244bdded3 Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Fri, 17 Jan 2025 16:56:27 -0300 Subject: [PATCH 12/14] Limpieza --- app/src/Service/Persona.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/Service/Persona.php b/app/src/Service/Persona.php index 5e8244e..fabc9da 100644 --- a/app/src/Service/Persona.php +++ b/app/src/Service/Persona.php @@ -9,7 +9,8 @@ use Psr\Log\LoggerInterface; class Persona extends Ideal\Service { - public function __construct(LoggerInterface $logger, protected Repository\Persona $personaRepository, + public function __construct(LoggerInterface $logger, + protected Repository\Persona $personaRepository, protected Repository\Persona\Datos $datosPersonaRepository) { parent::__construct($logger); -- 2.49.0 From 71615050f38c387cb36ffb352c30ad439f19f130 Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Fri, 17 Jan 2025 16:56:47 -0300 Subject: [PATCH 13/14] Agregando o buscando el cliente primero --- app/src/Service/Venta/Factura.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/Service/Venta/Factura.php b/app/src/Service/Venta/Factura.php index 7715810..8f5bc4b 100644 --- a/app/src/Service/Venta/Factura.php +++ b/app/src/Service/Venta/Factura.php @@ -7,13 +7,15 @@ use Incoviba\Common\Ideal; use Incoviba\Common\Implement; use Incoviba\Model; use Incoviba\Repository; +use Incoviba\Service; class Factura extends Ideal\Service { public function __construct(LoggerInterface $logger, protected Repository\Venta\Factura $facturaRepository, protected Repository\Venta\Factura\Estado $estadoRepository, - protected Repository\Venta\Factura\Estado\Tipo $tipoRepository) + protected Repository\Venta\Factura\Estado\Tipo $tipoRepository, + protected Service\Persona $personaService) { parent::__construct($logger); } @@ -57,6 +59,11 @@ class Factura extends Ideal\Service if ($factura !== null) { return $factura; } + list($data['cliente']['rut'], $data['cliente']['digito']) = explode('-', $data['cliente']['rut']); + $data['cliente']['rut'] = (int) str_replace('.', '', $data['cliente']['rut']); + $client = $this->personaService->add($data['cliente']); + $data['cliente_rut'] = $client->rut; + unset($data['cliente']); $factura = $this->facturaRepository->save($this->facturaRepository->create($data)); $tipo = $this->tipoRepository->fetchByDescripcion('generada'); $this->estadoRepository->save($this->estadoRepository->create([ -- 2.49.0 From 59a28a353b14e1636761cc00aedee0467e510074 Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Mon, 3 Feb 2025 22:17:57 -0300 Subject: [PATCH 14/14] Guardar factura --- .../views/ventas/facturacion/show.blade.php | 120 +++++++++++++++--- .../ventas/facturacion/show/factura.blade.php | 93 ++++++++------ .../facturacion/show/propietario.blade.php | 6 +- .../ventas/facturacion/show/unidad.blade.php | 4 +- .../ventas/facturacion/show/venta.blade.php | 25 ++-- app/src/Controller/API/Ventas/Facturas.php | 5 +- app/src/Model/Venta/Factura.php | 33 +++-- app/src/Repository/Venta/Factura.php | 97 ++++++++++---- app/src/Service/Persona.php | 15 ++- app/src/Service/Redis.php | 17 ++- app/src/Service/Venta/Factura.php | 3 +- 11 files changed, 296 insertions(+), 122 deletions(-) diff --git a/app/resources/views/ventas/facturacion/show.blade.php b/app/resources/views/ventas/facturacion/show.blade.php index 7b68876..d9bcaba 100644 --- a/app/resources/views/ventas/facturacion/show.blade.php +++ b/app/resources/views/ventas/facturacion/show.blade.php @@ -41,13 +41,18 @@ }, 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}) - }) + this.venta.watch().facturas() } } }, + proporcion() { + if (this.venta.props.facturas.facturas.length === 0) { + return 1 + } + return this.venta.props.facturas.facturas.reduce((sum, factura) => { + return sum + factura.props.proporcion + }, 0) + }, setup({ids}) { this.ids = ids this.venta = new Venta({ @@ -77,7 +82,7 @@ new Unidad({ id: {{$unidad->id}}, tipo: '{{ucwords($unidad->proyectoTipoUnidad->tipoUnidad->descripcion)}}', - descripcion: '{{$unidad->descripcion}}', + descripcion: '{{ucwords($unidad->proyectoTipoUnidad->tipoUnidad->descripcion)}} {{ $unidad->descripcion }} (UF {{ number_format($unidad->precio($venta->currentEstado()->fecha)->valor, 2) }})', prorrateo: {{$unidad->prorrateo}}, propiedad_unidad_id: {{$unidad->pu_id}}, valor: {{($unidad->valor > 0) ? $unidad->valor : $unidad->precio($venta->currentEstado()->fecha)->valor}} @@ -98,23 +103,100 @@ }) @if (count($facturas) > 0) this.venta.props.uf = { - fecha: new Date('{{$facturas[0]->fechaUF->format('Y-m-d')}}'), - valor: {{$facturas[0]->valorUF}} + fecha: new Date('{{$facturas[0]->uf->fecha->format('Y-m-d')}}'), + valor: {{$facturas[0]->uf->valor}} } @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({ + this.venta.props.facturas.facturas[{{$factura->index - 1}}] = new Factura({ + id: {{ $factura->id }}, + venta: this.venta.props, + index: {{$factura->index}}, + fecha: new Date('{{$factura->fecha->format('Y-m-d')}}'), + proporcion: {{$factura->proporcion}}, + emisor: { + rut: '{{$factura->venta->proyecto()->inmobiliaria()->rut}}', + nombre: '{{$factura->venta->proyecto()->inmobiliaria()->razon}}', + direccion: '{{$factura->venta->proyecto()->direccion()->simple()}}', + comuna: '{{$factura->venta->proyecto()->direccion()->comuna->id}}', + }, + receptor: { + rut: '{{$factura->cliente->rutCompleto()}}', + nombre: '{{$factura->cliente->nombreCompleto()}}', + direccion: '{{$factura->cliente->datos()->direccion->simple()}}', + comuna: '{{$factura->cliente->datos()->direccion->comuna->id}}', + }, + terreno: { + @if ($terreno->fecha != null) fecha: new Date('{{$terreno->fecha->add(new DateInterval('P1D'))->format('Y-m-d')}}'), + @else fecha: null, + @endif + valor: {{ $factura->terreno}} + }, + unidades: [ + @foreach ($factura->unidades as $unidad) + { + unidad: new Unidad({ + id: {{$unidad->unidad->id}}, + tipo: '{{ucwords($unidad->unidad->proyectoTipoUnidad->tipoUnidad->descripcion)}}', + descripcion: '{{ucwords($unidad->unidad->proyectoTipoUnidad->tipoUnidad->descripcion)}} {{ $unidad->unidad->descripcion }} (UF {{ number_format(array_values(array_filter($venta->propiedad()->unidades, function($uni) use ($unidad, $factura) {return $uni->id === $unidad->unidad->id;}))[0]->precio($venta->currentEstado()->fecha)->valor * $factura->proporcion, 2) }})', + prorrateo: {{$unidad->prorrateo}}, + propiedad_unidad_id: {{ array_values(array_filter($venta->propiedad()->unidades, function($uni) use ($unidad) {return $uni->id === $unidad->unidad->id;}))[0]->pu_id }}, + valor: {{$unidad->precio}} + }), + descripcion: '{{ucwords($unidad->unidad->proyectoTipoUnidad->tipoUnidad->descripcion)}} {{ $unidad->unidad->descripcion }} (UF {{ number_format(array_values(array_filter($venta->propiedad()->unidades, function($uni) use ($unidad, $factura) {return $uni->id === $unidad->unidad->id;}))[0]->precio($venta->currentEstado()->fecha)->valor * $factura->proporcion, 2) }})', + precio: {{ $unidad->precio }}, + prorrateo: {{ $unidad->prorrateo }}, + }, + @endforeach + ], + detalle: { + base: {{ $factura->base() }}, + terreno: {{ $factura->terreno * $factura->proporcion }}, + neto: {{ $factura->neto() }}, + iva: {{ $factura->iva() }}, + bruto: {{ $factura->bruto() }}, + total: {{ $factura->total() }}, + descuento: {{ array_reduce($factura->unidades, function($sum, $unidad) use ($factura) { return $sum + $unidad->prorrateo * $factura->proporcion; }, 0) }} + }, + total: { + neto: {{ array_reduce($factura->unidades, function($sum, $unidad) {return $sum + $unidad->precio * $factura->proporcion;}, 0) }}, + exento: {{ $factura->terreno * $factura->proporcion }}, + iva: {{ $factura->iva() }}, + total: {{ $factura->total() }} + }, + saved: true, + uf: { + fecha: new Date('{{$factura->uf->fecha->format('Y-m-d')}}'), + valor: {{$factura->uf->valor}} + } + }) + this.venta.props.facturas.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}}', + rut: '{{$factura->cliente->rutCompleto()}}', + nombre: '{{$factura->cliente->nombreCompleto()}}', + direccion: '{{$factura->cliente->datos()->direccion->simple()}}', + comuna: '{{$factura->cliente->datos()->direccion->comuna->id}}', fecha: new Date('{{$factura->fecha->format('Y-m-d')}}'), }) @endforeach - @else + this.draw().venta() + if (this.proporcion() < 1) { + const p = 1 - this.proporcion() + const propietario = this.venta.add().propietario({ + rut: '', + nombre: '', + proporcion: (p*100).toFixed(0)/100, + direccion: '', + comuna: '0' + }) + document.getElementById('propietarios').innerHTML = this.venta.draw().propietarios() + document.getElementById('cantidad_propietarios').value = this.venta.props.propietarios.length + this.venta.add().factura(propietario) + + this.draw().facturas() + } + @else const propietario = this.venta.add().propietario({ proporcion: 1, rut: '{{$venta->propietario()->rut()}}', @@ -122,11 +204,11 @@ direccion: '{{$venta->propietario()->datos->direccion->simple()}}', comuna: '{{$venta->propietario()->datos->direccion->comuna->id}}' }) + this.draw().venta() + if (typeof propietario !== 'undefined') { + this.venta.add().factura(propietario) + } @endif - this.draw().venta() - if (typeof propietario !== 'undefined') { - this.venta.add().factura(propietario) - } this.draw().facturas() } } diff --git a/app/resources/views/ventas/facturacion/show/factura.blade.php b/app/resources/views/ventas/facturacion/show/factura.blade.php index 1e3af6e..b039f68 100644 --- a/app/resources/views/ventas/facturacion/show/factura.blade.php +++ b/app/resources/views/ventas/facturacion/show/factura.blade.php @@ -89,11 +89,11 @@ rut: () => { return [ '
', - '
', + '
', '', `RUT:${this.props.emisor.rut.toUpperCase()}
`, 'FACTURA ELECTRÓNICA
', - `N° #${this.props.venta.id}${this.props.index}`, + `N° ${this.props.venta.id}${this.props.index}`, '
', '
', '
' @@ -128,34 +128,34 @@ table: ({formatters}) => { return [ '
', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - this.draw().unidades({formatters}), - '', - '', - '', - '', - '', - '', - '
DETALLES
DescripciónCant/UnidadPrec. Unit.IndTotal
', - '
', - '
', - '
', - '
', - '
', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + this.draw().unidades({formatters}), + '', + '', + '', + '', + '', + '', + '
DETALLES
DescripciónCant/UnidadPrec. Unit.IndTotal
', + '
', + '
', + '
', + '
', + '
', '
' ].join("\n") }, @@ -279,7 +279,7 @@ '
', '
', '
', - '
', + `
`, '', 'Guardada', '
', @@ -300,14 +300,30 @@ watch() { return { save: () => { - document.querySelector(`button[data-index="${this.props.index}"]`).addEventListener('click', clickEvent => { + document.querySelector(`.guardar[data-index="${this.props.index}"]`).addEventListener('click', clickEvent => { const index = clickEvent.currentTarget.getAttribute('data-index') - facturas.save().factura(index) + facturas.venta.save().factura({index: index - 1}) }) } } } + validate() { + if (this.props.venta.id === null || typeof this.props.venta.id === 'undefined') { + return false + } + if (this.props.index === null || typeof this.props.index === 'undefined') { + return false + } + if (this.props.proporcion === null || typeof this.props.proporcion === 'undefined') { + return false + } + return !(this.props.receptor.rut === '' || this.props.receptor.nombre === '' || this.props.receptor.direccion === '' || this.props.receptor.comuna === ''); + + } save() { + if (!this.validate()) { + return + } let url = '{{$urls->api}}/ventas/facturas/add' if (this.saved) { url = `{{$urls->api}}/ventas/facturas/${this.props.id}/edit` @@ -326,6 +342,7 @@ body.set('detalle', JSON.stringify(this.props.detalle)) body.set('total', JSON.stringify(this.props.total)) body.set('uf', JSON.stringify({fecha: [this.props.uf.fecha.getFullYear(), this.props.uf.fecha.getMonth()+1, this.props.uf.fecha.getDate()].join('-'), valor: this.props.uf.valor})) + return APIClient.fetch(url, {method, body}).then(response => { if (!response) { return @@ -366,7 +383,7 @@ unidades.forEach(unidad => { this.props.unidades.push({ unidad: unidad, - descripcion: unidad.descripcion(this.props.proporcion), + descripcion: unidad.changeDescripcion(this.props.proporcion || 1), precio: unidad.props.valor * this.props.uf.valor * this.props.proporcion, prorrateo: unidad.props.prorrateo * this.props.proporcion }) @@ -376,10 +393,10 @@ this.props.proporcion = propietario.props.proporcion this.props.receptor = { - rut: propietario.props.rut, - nombre: propietario.props.nombre, - direccion: propietario.props.direccion, - comuna: propietario.comuna + rut: propietario.props.rut ?? '', + nombre: propietario.props.nombre ?? '', + direccion: propietario.props.direccion ?? '', + comuna: propietario.comuna ?? '' } } } diff --git a/app/resources/views/ventas/facturacion/show/propietario.blade.php b/app/resources/views/ventas/facturacion/show/propietario.blade.php index f33fe56..03f076d 100644 --- a/app/resources/views/ventas/facturacion/show/propietario.blade.php +++ b/app/resources/views/ventas/facturacion/show/propietario.blade.php @@ -14,7 +14,11 @@ } get comuna() { - return $('#comuna_propietario'+this.props.index).dropdown('get text') ?? this.props.comuna + const comuna = $('#comuna_propietario'+this.props.index).dropdown('get text') + if (typeof comuna === 'string') { + return comuna + } + return this.props.comuna ?? '' } update() { return { diff --git a/app/resources/views/ventas/facturacion/show/unidad.blade.php b/app/resources/views/ventas/facturacion/show/unidad.blade.php index c290796..af57b94 100644 --- a/app/resources/views/ventas/facturacion/show/unidad.blade.php +++ b/app/resources/views/ventas/facturacion/show/unidad.blade.php @@ -13,8 +13,8 @@ this.props = props } - descripcion(proporcion = 1) { - return [this.props.tipo, this.props.descripcion, `[UF ${facturas.formatters.ufs.format(this.props.valor * proporcion)}]`].join(' ') + changeDescripcion(proporcion = 1) { + return this.descripcion = [this.props.tipo, this.props.descripcion, `[UF ${facturas.formatters.ufs.format(this.props.valor * proporcion)}]`].join(' ') } update() { return { diff --git a/app/resources/views/ventas/facturacion/show/venta.blade.php b/app/resources/views/ventas/facturacion/show/venta.blade.php index bfb8f4a..e3638f5 100644 --- a/app/resources/views/ventas/facturacion/show/venta.blade.php +++ b/app/resources/views/ventas/facturacion/show/venta.blade.php @@ -252,6 +252,11 @@ this.props.propietarios.forEach(propietario => { propietario.watch().propietario() }) + }, + facturas: () => { + this.props.facturas.facturas.forEach(factura => { + factura.watch().save() + }) } } } @@ -267,11 +272,11 @@ value: ufFormatter => { return [ '
', - '
', - '
', - 'Valor Venta: UF ' + ufFormatter.format(this.props.valor), - '
', - '
', + '
', + '
', + 'Valor Venta: UF ' + ufFormatter.format(this.props.valor), + '
', + '
', '
' ].join("\n") }, @@ -377,7 +382,7 @@ }, facturas: formatters => { const output = [] - this.props.facturas.facturas.forEach((factura, index) => { + this.props.facturas.facturas.forEach(factura => { output.push(factura.draw().factura({formatters})) }) return output.join("\n") @@ -405,10 +410,10 @@ comuna: this.props.inmobiliaria.comuna }, receptor: { - rut: '', - nombre: '', - direccion: '', - comuna: '' + rut: propietario.props.rut ?? '', + nombre: propietario.props.nombre ?? '', + direccion: propietario.props.direccion ?? '', + comuna: propietario.props.comuna ?? '' }, unidades: [], detalle: { diff --git a/app/src/Controller/API/Ventas/Facturas.php b/app/src/Controller/API/Ventas/Facturas.php index 8757bcd..6a5d9a1 100644 --- a/app/src/Controller/API/Ventas/Facturas.php +++ b/app/src/Controller/API/Ventas/Facturas.php @@ -21,12 +21,13 @@ class Facturas extends Controller 'success' => false ]; try { - foreach (['cliente', 'unidades', 'detalle', 'total', 'uf'] as $key) { + /*foreach (['cliente', 'unidades', 'detalle', 'total', 'uf'] as $key) { if (!isset($data[$key]) or empty($data[$key])) { continue; } $data[$key] = json_decode($data[$key], true); - } + }*/ + $data['cliente'] = json_decode($data['cliente'], true); $output['factura'] = $facturaService->add($data); $output['success'] = true; } catch (Implement\Exception\EmptyResult) { diff --git a/app/src/Model/Venta/Factura.php b/app/src/Model/Venta/Factura.php index f3d4d1b..a4d2f55 100644 --- a/app/src/Model/Venta/Factura.php +++ b/app/src/Model/Venta/Factura.php @@ -13,11 +13,11 @@ class Factura extends Ideal\Model public float $proporcion; public Model\Persona $cliente; - public DateTimeInterface $fecha; - public array $unidades; // [[unidad, descripcion, precio, prorrateo]] - public int $terreno; - public object $uf; // [fecha, valor] - public object $ipc; // [fecha, valor] + public ?DateTimeInterface $fecha = null; + public ?array $unidades = null; // [[unidad, descripcion, precio, prorrateo]] + public ?int $terreno = null; + public ?object $uf = null; // [fecha, valor] + public ?object $ipc = null; // [fecha, valor] protected array $estados; public function estados(): array @@ -28,23 +28,23 @@ class Factura extends Ideal\Model return $this->estados ?? []; } - public function total(): int + public function total(): float { return $this->venta->valor * $this->uf->valor * $this->proporcion; } - public function bruto(): int + public function bruto(): float { return $this->total() - $this->terreno * $this->proporcion; } - public function iva(): int + public function iva(): float { return $this->neto() * .19; } - public function neto(): int + public function neto(): float { return $this->bruto() / 1.19; } - public function base(): int + public function base(): float { return $this->neto() + $this->terreno * $this->proporcion; } @@ -59,7 +59,7 @@ class Factura extends Ideal\Model 'total' => $this->total(), 'descuento' => array_reduce($this->unidades, function($sum, $unidad) { return $sum + $unidad->prorrateo * $this->proporcion; - }) + }, 0) ]; } public function totales(): array @@ -89,18 +89,17 @@ class Factura extends Ideal\Model 'receptor' => [ 'rut' => $this->cliente->rutCompleto(), 'nombre' => $this->cliente->nombreCompleto(), - 'direccion' => $this->cliente->datos()->direccion->simple(), - 'comuna' => $this->cliente->datos()->direccion->comuna->descripcion + 'direccion' => $this->cliente->datos()->direccion?->simple(), + 'comuna' => $this->cliente->datos()->direccion?->comuna->descripcion ], - 'fecha' => $this->fecha->format('Y-m-d'), + 'fecha' => $this->fecha?->format('Y-m-d'), 'unidades' => $this->unidades, 'detalle' => $this->detalle(), 'total' => $this->totales(), 'uf' => [ - 'fecha' => $this->uf->fecha->format('Y-m-d'), - 'valor' => $this->uf->valor + 'fecha' => $this->uf?->fecha->format('Y-m-d'), + 'valor' => $this->uf?->valor ], - 'estados' => $this->estados() ]); } diff --git a/app/src/Repository/Venta/Factura.php b/app/src/Repository/Venta/Factura.php index 97ee81c..d094ebd 100644 --- a/app/src/Repository/Venta/Factura.php +++ b/app/src/Repository/Venta/Factura.php @@ -9,10 +9,12 @@ use Incoviba\Common\Implement; use Incoviba\Common\Implement\Exception\EmptyResult; use Incoviba\Model; use Incoviba\Repository; +use Incoviba\Service; class Factura extends Ideal\Repository { public function __construct(Implement\Connection $connection, protected Repository\Venta $ventaRepository, + protected Service\Persona $personaService, protected Repository\Persona $personaRepository, protected Unidad $unidadRepository) { parent::__construct($connection); @@ -30,31 +32,67 @@ class Factura extends Ideal\Repository ->register('cliente_rut', (new Implement\Repository\Mapper()) ->setProperty('cliente') ->setFunction(function($data) { - return $this->personaRepository->fetchById($data['cliente_rut']); + return $this->personaService->getById($data['cliente_rut']); })); $factura = $this->parseData(new Model\Venta\Factura(), $data, $map); - return $this->createDatos($factura); + return $this->createDatos($factura, $data); } - public function createDatos(Model\Venta\Factura &$factura): Model\Venta\Factura + public function createDatos(Model\Venta\Factura &$factura, ?array $data = null): Model\Venta\Factura { try { $result = $this->getDatos($factura->venta->id); - $factura->fecha = new DateTimeImmutable($result['fecha']); - $factura->uf = json_decode($result['uf']); - $factura->uf->fecha = new DateTimeImmutable($factura->uf->fecha); - $factura->ipc = json_decode($result['ipc']); - $factura->ipc->fecha = new DateTimeImmutable($factura->ipc->fecha); - $factura->unidades = array_map(function($datos) use ($factura) { - $unidad = $this->unidadRepository->fetchById($datos->unidad_id); - return (object) [ - 'unidad' => $unidad, - 'descripcion' => implode(' ', [ucwords($unidad->proyectoTipoUnidad->tipoUnidad->descripcion), $unidad->descripcion]), - 'precio' => $datos->precio, - 'prorrateo' => $datos->prorrateo - ]; - }, json_decode($result['unidades'])); - $factura->terreno = $result['terreno']; - } catch (EmptyResult) {} + if ($result['fecha'] !== null) { + $factura->fecha = new DateTimeImmutable($result['fecha']); + } + if ($result['uf'] !== null) { + $factura->uf = json_decode($result['uf']); + $factura->uf->fecha = new DateTimeImmutable($factura->uf->fecha); + } + if ($result['ipc'] !== null) { + $factura->ipc = json_decode($result['ipc']); + $factura->ipc->fecha = new DateTimeImmutable($factura->ipc->fecha); + } + if ($result['unidades'] !== null) { + $factura->unidades = array_map(function($datos) use ($factura) { + $unidad = $this->unidadRepository->fetchById($datos->unidad_id); + return (object) [ + 'unidad' => $unidad, + 'descripcion' => implode(' ', [ucwords($unidad->proyectoTipoUnidad->tipoUnidad->descripcion), $unidad->descripcion]), + 'precio' => $datos->precio, + 'prorrateo' => $datos->prorrateo + ]; + }, json_decode($result['unidades'])); + } + if ($result['terreno'] !== null) { + $factura->terreno = $result['terreno']; + } + } catch (EmptyResult) { + if (isset($data['fecha'])) { + $factura->fecha = new DateTimeImmutable($data['fecha']); + } + if (isset($data['uf'])) { + $factura->uf = json_decode($data['uf']); + $factura->uf->fecha = new DateTimeImmutable($factura->uf->fecha); + } + if (isset($data['ipc'])) { + $factura->ipc = json_decode($data['ipc']); + $factura->ipc->fecha = new DateTimeImmutable($factura->ipc->fecha); + } + if (isset($data['unidades'])) { + $factura->unidades = array_map(function($datos) use ($factura) { + $unidad = $this->unidadRepository->fetchById($datos->unidad_id); + return (object) [ + 'unidad' => $unidad, + 'descripcion' => implode(' ', [ucwords($unidad->proyectoTipoUnidad->tipoUnidad->descripcion), $unidad->descripcion]), + 'precio' => $datos->precio, + 'prorrateo' => $datos->prorrateo + ]; + }, json_decode($data['unidades'])); + } + if (isset($data['terreno'])) { + $factura->terreno = (int) $data['terreno']; + } + } return $factura; } @@ -93,20 +131,27 @@ class Factura extends Ideal\Repository $query = $this->connection->getQueryBuilder() ->insert() ->into('venta_datos_facturas') + ->columns([ + 'venta_id', + 'fecha', + 'unidades', + 'terreno', + 'uf', + 'ipc' + ]) ->values([ 'venta_id' => $factura->venta->id, - 'index' => $factura->index, - 'proporcion' => $factura->proporcion, - 'unidades' => json_encode(array_map(function($unidad) { + 'fecha' => $factura->fecha?->format('Y-m-d'), + 'unidades' => (isset($factura->unidades)) ? json_encode(array_map(function($unidad) { return [ 'unidad_id' => $unidad->unidad->id, 'precio' => $unidad->precio, 'prorrateo' => $unidad->prorrateo ]; - }, $factura->unidades)), - 'terreno' => $factura->terreno, - 'uf' => json_encode($factura->uf), - 'ipc' => json_encode($factura->ipc) + }, $factura?->unidades)) : null, + 'terreno' => $factura?->terreno, + 'uf' => (isset($factura->uf)) ? json_encode(['fecha' => $factura->uf?->fecha->format('Y-m-d'), 'valor' => $factura->uf?->valor]) : null, + 'ipc' => (isset($factura->ipc)) ? json_encode(['fecha' => $factura->ipc?->fecha->format('Y-m-d'), 'valor' => $factura->ipc?->valor]) : null ]); $this->connection->execute($query); } diff --git a/app/src/Service/Persona.php b/app/src/Service/Persona.php index fabc9da..39733a6 100644 --- a/app/src/Service/Persona.php +++ b/app/src/Service/Persona.php @@ -11,7 +11,8 @@ class Persona extends Ideal\Service { public function __construct(LoggerInterface $logger, protected Repository\Persona $personaRepository, - protected Repository\Persona\Datos $datosPersonaRepository) + protected Repository\Persona\Datos $datosPersonaRepository, + protected Repository\Venta\Propietario $propietarioRepository) { parent::__construct($logger); } @@ -25,11 +26,21 @@ class Persona extends Ideal\Service try { $persona = $this->personaRepository->fetchById($data['rut']); } catch (Implement\Exception\EmptyResult) { + try { + $propietario = $this->propietarioRepository->fetchById($data['rut']); + $data['nombres'] = $propietario->nombres; + $data['apellido_paterno'] = $propietario->apellidos['paterno']; + $data['apellido_materno'] = $propietario->apellidos['materno']; + $data['direccion_id'] = $propietario->datos->direccion->id; + } catch (Implement\Exception\EmptyResult) {} $persona = $this->personaRepository->create($data); $persona = $this->personaRepository->save($persona); } - if (isset($data['email']) or isset($data['telefono'])) { + if (isset($data['direccion_id']) or isset($data['email']) or isset($data['telefono'])) { $datosData = ['persona_rut' => $persona->rut]; + if (isset($data['direccion_id'])) { + $datosData['direccion_id'] = $data['direccion_id']; + } if (isset($data['email'])) { $datosData['email'] = $data['email']; } diff --git a/app/src/Service/Redis.php b/app/src/Service/Redis.php index 5f85f0e..6b14761 100644 --- a/app/src/Service/Redis.php +++ b/app/src/Service/Redis.php @@ -3,6 +3,7 @@ namespace Incoviba\Service; use Predis\ClientInterface; use Incoviba\Common\Implement\Exception\EmptyRedis; +use Predis\Connection\ConnectionException; class Redis { @@ -10,13 +11,21 @@ class Redis public function get(string $name): mixed { - if (!$this->client->exists($name)) { - throw new EmptyRedis($name); + try { + if (!$this->client->exists($name)) { + throw new EmptyRedis($name); + } + return $this->client->get($name); + } catch (ConnectionException $exception) { + throw new EmptyRedis($name, $exception); } - return $this->client->get($name); } public function set(string $name, mixed $value, int $expirationTTL = 60 * 60 * 24): void { - $this->client->set($name, $value, 'EX', $expirationTTL); + try { + $this->client->set($name, $value, 'EX', $expirationTTL); + } catch (ConnectionException) { + return; + } } } diff --git a/app/src/Service/Venta/Factura.php b/app/src/Service/Venta/Factura.php index 8f5bc4b..e5bcc84 100644 --- a/app/src/Service/Venta/Factura.php +++ b/app/src/Service/Venta/Factura.php @@ -64,7 +64,8 @@ class Factura extends Ideal\Service $client = $this->personaService->add($data['cliente']); $data['cliente_rut'] = $client->rut; unset($data['cliente']); - $factura = $this->facturaRepository->save($this->facturaRepository->create($data)); + $factura = $this->facturaRepository->create($data); + $factura = $this->facturaRepository->save($factura); $tipo = $this->tipoRepository->fetchByDescripcion('generada'); $this->estadoRepository->save($this->estadoRepository->create([ 'factura_id' => $factura->id, -- 2.49.0