diff --git a/app/common/Ideal/Model.php b/app/common/Ideal/Model.php
index c68827a..ec2c59b 100644
--- a/app/common/Ideal/Model.php
+++ b/app/common/Ideal/Model.php
@@ -26,7 +26,7 @@ abstract class Model implements Define\Model
public function jsonSerialize(): mixed
{
return [
- 'id' => $this->id,
+ 'id' => $this->id ?? '',
...$this->jsonComplement()
];
}
diff --git a/app/common/Implement/Repository/Factory.php b/app/common/Implement/Repository/Factory.php
index 00fd799..10ec520 100644
--- a/app/common/Implement/Repository/Factory.php
+++ b/app/common/Implement/Repository/Factory.php
@@ -2,7 +2,9 @@
namespace Incoviba\Common\Implement\Repository;
use Closure;
+use Exception;
use Incoviba\Common\Define;
+use Incoviba\Common\Implement\Exception\EmptyResult;
class Factory implements Define\Repository\Factory
{
@@ -20,8 +22,16 @@ class Factory implements Define\Repository\Factory
return $this;
}
+ /**
+ * @return mixed
+ * @throws EmptyResult
+ */
public function run(): mixed
{
- return call_user_func_array($this->callable, $this->args);
+ try {
+ return call_user_func_array($this->callable, $this->args);
+ } catch (Exception $exception) {
+ throw new EmptyResult($exception->getMessage(), $exception);
+ }
}
}
diff --git a/app/resources/database/migrations/20250215133437_create_reservation.php b/app/resources/database/migrations/20250215133437_create_reservations.php
similarity index 78%
rename from app/resources/database/migrations/20250215133437_create_reservation.php
rename to app/resources/database/migrations/20250215133437_create_reservations.php
index db9c32a..1a8dec7 100644
--- a/app/resources/database/migrations/20250215133437_create_reservation.php
+++ b/app/resources/database/migrations/20250215133437_create_reservations.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
-final class CreateReservation extends AbstractMigration
+final class CreateReservations extends AbstractMigration
{
/**
* Change Method.
@@ -23,9 +23,11 @@ final class CreateReservation extends AbstractMigration
$this->execute("ALTER DATABASE CHARACTER SET 'utf8mb4';");
$this->execute("ALTER DATABASE COLLATE='utf8mb4_general_ci';");
- $this->table('reservation')
+ $this->table('reservations')
+ ->addColumn('project_id', 'integer', ['signed' => false, 'null' => false])
->addColumn('buyer_rut', 'integer', ['signed' => false, 'null' => false])
->addColumn('date', 'date', ['null' => false])
+ ->addForeignKey('project_id', 'proyecto', 'id', ['delete' => 'cascade', 'update' => 'cascade'])
->addForeignKey('buyer_rut', 'personas', 'rut', ['delete' => 'cascade', 'update' => 'cascade'])
->create();
diff --git a/app/resources/database/migrations/20250215135457_create_reservation_datas.php b/app/resources/database/migrations/20250215135457_create_reservation_details.php
similarity index 73%
rename from app/resources/database/migrations/20250215135457_create_reservation_datas.php
rename to app/resources/database/migrations/20250215135457_create_reservation_details.php
index ad85f98..3bdcac7 100644
--- a/app/resources/database/migrations/20250215135457_create_reservation_datas.php
+++ b/app/resources/database/migrations/20250215135457_create_reservation_details.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
-final class CreateReservationDatas extends AbstractMigration
+final class CreateReservationDetails extends AbstractMigration
{
/**
* Change Method.
@@ -23,11 +23,13 @@ final class CreateReservationDatas extends AbstractMigration
$this->execute("ALTER DATABASE CHARACTER SET 'utf8mb4';");
$this->execute("ALTER DATABASE COLLATE='utf8mb4_general_ci';");
- $this->table('reservation_data')
+ $this->table('reservation_details')
->addColumn('reservation_id', 'integer', ['signed' => false, 'null' => false])
->addColumn('type', 'integer', ['length' => 1, 'signed' => false, 'null' => false])
->addColumn('reference_id', 'integer', ['signed' => false, 'null' => false])
- ->addColumn('value', 'decimal', ['precision' => 10, 'scale' => 2, 'signed' => false, 'default' => 0.00, 'null' => true])
+ ->addColumn('value', 'decimal', ['precision' => 10, 'scale' => 2, 'signed' => false, 'default' => null, 'null' => true])
+ ->addForeignKey('reservation_id', 'reservations', 'id', ['delete' => 'cascade', 'update' => 'cascade'])
+ ->addIndex(['reservation_id', 'type', 'reference_id'], ['unique' => true, 'name' => 'idx_reservation_details'])
->create();
$this->execute('SET unique_checks=1; SET foreign_key_checks=1;');
diff --git a/app/resources/database/migrations/20250215135822_create_reservation_states.php b/app/resources/database/migrations/20250215135822_create_reservation_states.php
index e617ef5..490d3dc 100644
--- a/app/resources/database/migrations/20250215135822_create_reservation_states.php
+++ b/app/resources/database/migrations/20250215135822_create_reservation_states.php
@@ -27,7 +27,7 @@ final class CreateReservationStates extends AbstractMigration
->addColumn('reservation_id', 'integer', ['signed' => false, 'null' => false])
->addColumn('date', 'date', ['null' => false])
->addColumn('type', 'integer', ['length' => 3, 'null' => false, 'default' => 0])
- ->addForeignKey('reservation_id', 'reservation', 'id', ['delete' => 'cascade', 'update' => 'cascade'])
+ ->addForeignKey('reservation_id', 'reservations', 'id', ['delete' => 'cascade', 'update' => 'cascade'])
->create();
$this->execute('SET unique_checks=1; SET foreign_key_checks=1;');
diff --git a/app/resources/database/migrations/20250805212635_add_comments_to_estado_cierre.php b/app/resources/database/migrations/20250805212635_add_comments_to_estado_cierre.php
new file mode 100644
index 0000000..bbd9cae
--- /dev/null
+++ b/app/resources/database/migrations/20250805212635_add_comments_to_estado_cierre.php
@@ -0,0 +1,29 @@
+table('estado_cierre_comentarios')
+ ->addColumn('estado_cierre_id', 'integer', ['signed' => false])
+ ->addColumn('fecha', 'datetime', ['default' => 'CURRENT_TIMESTAMP'])
+ ->addColumn('comments', 'text')
+ ->addForeignKey('estado_cierre_id', 'estado_cierre', 'id', ['delete' => 'cascade', 'update' => 'cascade'])
+ ->create();
+ }
+}
diff --git a/app/resources/routes/api/personas.php b/app/resources/routes/api/personas.php
new file mode 100644
index 0000000..b01069c
--- /dev/null
+++ b/app/resources/routes/api/personas.php
@@ -0,0 +1,7 @@
+group('/personas', function($app) {});
+$app->group('/persona/{rut}', function($app) {
+ $app->get('[/]', [Personas::class, 'get']);
+});
diff --git a/app/resources/routes/api/proyectos.php b/app/resources/routes/api/proyectos.php
index 15d0445..5ff5f90 100644
--- a/app/resources/routes/api/proyectos.php
+++ b/app/resources/routes/api/proyectos.php
@@ -30,4 +30,5 @@ $app->group('/proyecto/{proyecto_id}', function($app) {
$app->post('/edit[/]', [Proyectos::class, 'terreno']);
});
$app->get('/brokers', [Proyectos::class, 'brokers']);
+ $app->get('/promotions', [Proyectos::class, 'promotions']);
});
diff --git a/app/resources/routes/api/ventas/reservations.php b/app/resources/routes/api/ventas/reservations.php
index 7e2e194..31ce261 100644
--- a/app/resources/routes/api/ventas/reservations.php
+++ b/app/resources/routes/api/ventas/reservations.php
@@ -3,10 +3,19 @@ use Incoviba\Controller\API\Ventas\Reservations;
$app->group('/reservations', function($app) {
$app->post('/add[/]', [Reservations::class, 'add']);
+ $app->group('/project/{project_id}', function($app) {
+ $app->get('/active[/]', [Reservations::class, 'active']);
+ $app->get('/pending[/]', [Reservations::class, 'pending']);
+ $app->get('/rejected[/]', [Reservations::class, 'rejected']);
+ });
$app->get('[/]', Reservations::class);
});
+$app->post('/reservation/add[/]', [Reservations::class, 'addOne']);
$app->group('/reservation/{reservation_id}', function($app) {
+ $app->get('/approve[/]', [Reservations::class, 'approve']);
+ $app->get('/reject[/]', [Reservations::class, 'reject']);
$app->post('/edit[/]', [Reservations::class, 'edit']);
+ $app->delete('/remove[/]', [Reservations::class, 'remove']);
$app->delete('[/]', [Reservations::class, 'delete']);
$app->get('[/]', [Reservations::class, 'get']);
});
diff --git a/app/resources/routes/ventas/cierres.php b/app/resources/routes/ventas/cierres.php
index 62e3084..2320f3d 100644
--- a/app/resources/routes/ventas/cierres.php
+++ b/app/resources/routes/ventas/cierres.php
@@ -1,7 +1,9 @@
group('/cierres', function($app) {
+ $app->get('/project/{project_id}', Cierres::class);
$app->get('[/]', Cierres::class);
});
$app->group('/cierre/{cierre_id}', function($app) {
diff --git a/app/resources/views/layout/body/scripts/rut.blade.php b/app/resources/views/layout/body/scripts/rut.blade.php
index a6b86c1..0045e4b 100644
--- a/app/resources/views/layout/body/scripts/rut.blade.php
+++ b/app/resources/views/layout/body/scripts/rut.blade.php
@@ -24,6 +24,12 @@
rut.replace(/\D/g, '')
return rut.replace(/^(\d{1,2})(\d{3})(\d{3})$/, '$1.$2.$3')
}
+ static clean(rut) {
+ if (!(typeof rut === 'string' || rut instanceof String)) {
+ rut = rut.toString()
+ }
+ return rut.replace(/\D/g, '')
+ }
static validar(rut, digito) {
if (!(typeof digito === 'string' || digito instanceof String)) {
digito = digito.toString()
diff --git a/app/resources/views/ventas/reservations.blade.php b/app/resources/views/ventas/reservations.blade.php
new file mode 100644
index 0000000..a7f2cc4
--- /dev/null
+++ b/app/resources/views/ventas/reservations.blade.php
@@ -0,0 +1,664 @@
+@extends('layout.base')
+
+@section('page_title')
+ Cierres - Reservas
+@endsection
+
+@section('page_content')
+
+
+
+
+
+ @if (count($projects) == 0)
+
+ No hay proyectos en venta.
+
+ @else
+
+ @foreach ($projects as $project)
+
+ {{ $project->descripcion }}
+
+ @endforeach
+
+ @endif
+
+
+
+
+
+
+
+
+
+ Unidades |
+ Cliente |
+ Fecha |
+ Oferta |
+ ¿Valida? |
+ Operador |
+ |
+
+
+
+
+
+
+
+
+
+ Unidades |
+ Cliente |
+ Fecha |
+ Oferta |
+ Operador |
+ |
+
+
+
+
+
+
+
+
+
+ Unidades |
+ Cliente |
+ Fecha |
+ Oferta |
+ Estado |
+ Operador |
+ Comentarios |
+
+
+
+
+
+
+
+
+ @include('ventas.reservations.modal.add')
+@endsection
+
+@push('page_styles')
+
+@endpush
+
+@push('page_scripts')
+
+@endpush
diff --git a/app/resources/views/ventas/reservations/modal/add.blade.php b/app/resources/views/ventas/reservations/modal/add.blade.php
new file mode 100644
index 0000000..4c7fcf2
--- /dev/null
+++ b/app/resources/views/ventas/reservations/modal/add.blade.php
@@ -0,0 +1,758 @@
+
+
+
+
+
+ Cancelar
+
+
+ Agregar
+
+
+
+
+@include('layout.body.scripts.rut')
+
+@push('page_scripts')
+
+@endpush
diff --git a/app/src/Controller/API/Personas.php b/app/src/Controller/API/Personas.php
new file mode 100644
index 0000000..ab424a9
--- /dev/null
+++ b/app/src/Controller/API/Personas.php
@@ -0,0 +1,34 @@
+ $rut,
+ 'persona' => null,
+ 'success' => false
+ ];
+ try {
+ $persona = $personaService->getById($rut);
+ $output['persona'] = $persona;
+ $output['success'] = true;
+ } catch (ServiceAction\Read $exception) {
+ $this->logger->error($exception->getMessage(), ['exception' => $exception]);
+ }
+
+ return $this->withJson($response, $output);
+ }
+}
diff --git a/app/src/Controller/API/Proyectos.php b/app/src/Controller/API/Proyectos.php
index e6994ec..d30adb8 100644
--- a/app/src/Controller/API/Proyectos.php
+++ b/app/src/Controller/API/Proyectos.php
@@ -187,5 +187,18 @@ class Proyectos
}
return $this->withJson($response, $output);
}
-
+ public function promotions(ServerRequestInterface $request, ResponseInterface $response,
+ Service\Venta\Promotion $promotionService, int $proyecto_id): ResponseInterface
+ {
+ $output = [
+ 'project_id' => $proyecto_id,
+ 'promotions' => []
+ ];
+ try {
+ $output['promotions'] = $promotionService->getByProject($proyecto_id);
+ } catch (Read $exception) {
+ return $this->withError($response, $exception);
+ }
+ return $this->withJson($response, $output);
+ }
}
diff --git a/app/src/Controller/API/Ventas/Reservations.php b/app/src/Controller/API/Ventas/Reservations.php
index 01c65db..607be0f 100644
--- a/app/src/Controller/API/Ventas/Reservations.php
+++ b/app/src/Controller/API/Ventas/Reservations.php
@@ -11,7 +11,8 @@ class Reservations
{
use withJson;
- public function __invoke(ServerRequestInterface $request, ResponseInterface $response, Service\Venta\Reservation $reservationService): ResponseInterface
+ public function __invoke(ServerRequestInterface $request, ResponseInterface $response,
+ Service\Venta\Reservation $reservationService): ResponseInterface
{
$reservations = [];
try {
@@ -22,6 +23,18 @@ class Reservations
return $this->withJson($response, compact('reservations'));
}
+ public function getByProject(ServerRequestInterface $request, ResponseInterface $response,
+ Service\Venta\Reservation $reservationService, int $project_id): ResponseInterface
+ {
+ $reservations = [];
+ try {
+ $reservations = $reservationService->getByProject($project_id);
+ } catch (ServiceAction\Read $exception) {
+ return $this->withError($response, $exception);
+ }
+
+ return $this->withJson($response, compact('reservations'));
+ }
public function get(ServerRequestInterface $request, ResponseInterface $response, Service\Venta\Reservation $reservationService, int $reservation_id): ResponseInterface
{
$output = [
@@ -47,8 +60,8 @@ class Reservations
'partial' => false,
'errors' => [],
];
-
- try {
+ var_dump($input);
+ /*try {
$output['reservations'] []= [
'reservation' => $reservationService->add($input),
'success' => true
@@ -56,7 +69,7 @@ class Reservations
$output['partial'] = true;
} catch (ServiceAction\Create $exception) {
$output['errors'] []= $this->parseError($exception);
- }
+ }*/
if (count($input['reservations']) === count($output['reservations'])) {
$output['success'] = true;
@@ -64,6 +77,31 @@ class Reservations
return $this->withJson($response, $output);
}
+ public function addOne(ServerRequestInterface $request, ResponseInterface $response, Service\Venta\Reservation $reservationService): ResponseInterface
+ {
+ $input = $request->getParsedBody();
+ $output = [
+ 'input' => $input,
+ 'reservation' => null,
+ 'success' => false,
+ 'errors' => [],
+ ];
+ $data = [];
+ foreach ($input as $key => $value) {
+ if (!str_starts_with($key, 'add_')) {
+ continue;
+ }
+ $data[substr($key, 4)] = $value;
+ }
+ try {
+ $output['reservation'] = $reservationService->add($data);
+ $output['success'] = true;
+ } catch (ServiceAction\Create $exception) {
+ $output['errors'] []= $this->parseError($exception);
+ }
+
+ return $this->withJson($response, $output);
+ }
public function edit(ServerRequestInterface $request, ResponseInterface $response, Service\Venta\Reservation $reservationService, int $reservation_id): ResponseInterface
{
$input = $request->getParsedBody();
@@ -100,4 +138,76 @@ class Reservations
return $this->withJson($response, $output);
}
+
+ public function active(ServerRequestInterface $request, ResponseInterface $response,
+ Service\Venta\Reservation $reservationService, int $project_id): ResponseInterface
+ {
+ $output = [
+ 'project_id' => $project_id,
+ 'reservations' => [],
+ 'success' => false,
+ ];
+ try {
+ $output['reservations'] = $reservationService->getActive($project_id);
+ $output['success'] = true;
+ } catch (ServiceAction\Read) {}
+ return $this->withJson($response, $output);
+ }
+ public function pending(ServerRequestInterface $request, ResponseInterface $response,
+ Service\Venta\Reservation $reservationService, int $project_id): ResponseInterface
+ {
+ $output = [
+ 'project_id' => $project_id,
+ 'reservations' => [],
+ 'success' => false,
+ ];
+ try {
+ $output['reservations'] = $reservationService->getPending($project_id);
+ $output['success'] = true;
+ } catch (ServiceAction\Read) {}
+ return $this->withJson($response, $output);
+ }
+ public function rejected(ServerRequestInterface $request, ResponseInterface $response,
+ Service\Venta\Reservation $reservationService, int $project_id): ResponseInterface
+ {
+ $output = [
+ 'project_id' => $project_id,
+ 'reservations' => [],
+ 'success' => false,
+ ];
+ try {
+ $output['reservations'] = $reservationService->getRejected($project_id);
+ $output['success'] = true;
+ } catch (ServiceAction\Read) {}
+ return $this->withJson($response, $output);
+ }
+
+ public function approve(ServerRequestInterface $request, ResponseInterface $response,
+ Service\Venta\Reservation $reservationService, int $reservation_id): ResponseInterface
+ {
+ $output = [
+ 'reservation_id' => $reservation_id,
+ 'success' => false,
+ ];
+ try {
+ $reservation = $reservationService->get($reservation_id);
+ $reservationService->approve($reservation);
+ $output['success'] = true;
+ } catch (ServiceAction\Read | ServiceAction\Update) {}
+ return $this->withJson($response, $output);
+ }
+ public function reject(ServerRequestInterface $request, ResponseInterface $response,
+ Service\Venta\Reservation $reservationService, int $reservation_id): ResponseInterface
+ {
+ $output = [
+ 'reservation_id' => $reservation_id,
+ 'success' => false,
+ ];
+ try {
+ $reservation = $reservationService->get($reservation_id);
+ $reservationService->reject($reservation);
+ $output['success'] = true;
+ } catch (ServiceAction\Read | ServiceAction\Update) {}
+ return $this->withJson($response, $output);
+ }
}
diff --git a/app/src/Controller/Ventas/Reservations.php b/app/src/Controller/Ventas/Reservations.php
new file mode 100644
index 0000000..bcdac5c
--- /dev/null
+++ b/app/src/Controller/Ventas/Reservations.php
@@ -0,0 +1,28 @@
+getVendibles('descripcion');
+ } catch (Read) {}
+ $regions = [];
+ try {
+ $regions = $regionRepository->fetchAll();
+ } catch (EmptyResult) {}
+ return $view->render($response, 'ventas.reservations', compact('projects', 'regions', 'project_id'));
+ }
+}
diff --git a/app/src/Exception/Model/InvalidState.php b/app/src/Exception/Model/InvalidState.php
new file mode 100644
index 0000000..3c82782
--- /dev/null
+++ b/app/src/Exception/Model/InvalidState.php
@@ -0,0 +1,13 @@
+datos)) {
- $this->datos = $this->runFactory('datos');
+ try {
+ $this->datos = $this->runFactory('datos');
+ } catch (EmptyResult) {
+ $this->datos = null;
+ }
}
return $this->datos;
}
public function __get(string $name): mixed
{
- if (property_exists($this, $name)) {
- return $this->{$name};
- }
if ($name === 'datos') {
return $this->datos();
}
if ($name === 'dv') {
return $this->digito;
}
+ if (property_exists($this, $name)) {
+ return $this->{$name};
+ }
throw new InvalidArgumentException("Property {$name} is not found in " . __CLASS__);
}
diff --git a/app/src/Model/Persona/Datos.php b/app/src/Model/Persona/Datos.php
index 7158d39..3fa1df4 100644
--- a/app/src/Model/Persona/Datos.php
+++ b/app/src/Model/Persona/Datos.php
@@ -21,10 +21,11 @@ class Datos extends Ideal\Model
public function jsonSerialize(): mixed
{
return [
+ 'persona_rut' => $this->persona->rut,
'direccion' => $this->direccion ?? null,
'telefono' => $this->telefono ?? null,
'email' => $this->email ?? null,
- 'fechaNacimiento' => $this->fechaNacimiento ?? null,
+ 'fechaNacimiento' => $this->fechaNacimiento?->format('Y-m-d') ?? null,
'sexo' => $this->sexo ?? null,
'estadoCivil' => $this->estadoCivil ?? null,
'nacionalidad' => $this->nacionalidad ?? null,
diff --git a/app/src/Model/Proyecto/Broker.php b/app/src/Model/Proyecto/Broker.php
index e55df74..342e668 100644
--- a/app/src/Model/Proyecto/Broker.php
+++ b/app/src/Model/Proyecto/Broker.php
@@ -1,7 +1,10 @@
contracts;
}
+ public function getContract(Proyecto $proyecto, ?DateTimeInterface $date = null): ?Proyecto\Broker\Contract
+ {
+ if ($date === null) {
+ $date = new DateTimeImmutable();
+ }
+ $contracts = $this->contracts();
+ $valid = array_filter($contracts, fn(Proyecto\Broker\Contract $contract) => $contract->project->id === $proyecto->id);
+ $valid = array_filter($valid, fn(Proyecto\Broker\Contract $contract) => $contract->wasActive($date));
+ if (count($valid) === 0) {
+ return null;
+ }
+ return last($valid);
+ }
+
+ public function applyCommission(Proyecto $proyecto, float $price, ?DateTimeInterface $date = null): float
+ {
+ $contract = $this->getContract($proyecto, $date);
+ if ($contract === null) {
+ return $price;
+ }
+ return $contract->activate()->apply($proyecto, $price);
+ }
+ public function reverseCommission(Proyecto $proyecto, float $price, ?DateTimeInterface $date = null): float
+ {
+ $contract = $this->getContract($proyecto, $date);
+ if ($contract === null) {
+ return $price;
+ }
+ return $contract->activate()->reverse($proyecto, $price);
+ }
public function rutFull(): string
{
diff --git a/app/src/Model/Proyecto/Broker/Contract.php b/app/src/Model/Proyecto/Broker/Contract.php
index 89f6014..feb5625 100644
--- a/app/src/Model/Proyecto/Broker/Contract.php
+++ b/app/src/Model/Proyecto/Broker/Contract.php
@@ -1,6 +1,7 @@
promotions;
}
+ public function isActive(): bool
+ {
+ $state = $this->current();
+ return $state !== null and $state->isActive();
+ }
+ public function activate(): self
+ {
+ $this->current()->activate();
+ return $this;
+ }
+ public function wasActive(DateTimeInterface $date): bool
+ {
+ $states = $this->states();
+ return array_any($states, fn($state) => $state->date <= $date);
+ }
+
+ public function value(float $price): float
+ {
+ if (!$this->isActive()) {
+ return $price;
+ }
+ return $price * (1 + $this->commission);
+ }
+ public function inverse(float $price): float
+ {
+ if (!$this->isActive()) {
+ return $price;
+ }
+ return $price / (1 + $this->commission);
+ }
+ public function apply(Model\Proyecto $project, float $price): float
+ {
+ if (!$this->isActive() or $this->project->id !== $project->id) {
+ return $price;
+ }
+ return $this->value($price);
+ }
+ public function reverse(Model\Proyecto $project, float $price): float
+ {
+ if (!$this->isActive() or $this->project->id !== $project->id) {
+ return $price;
+ }
+ return $this->inverse($price);
+ }
+
protected function jsonComplement(): array
{
return [
diff --git a/app/src/Model/Proyecto/Broker/Contract/State.php b/app/src/Model/Proyecto/Broker/Contract/State.php
index c773d6d..c3a982c 100644
--- a/app/src/Model/Proyecto/Broker/Contract/State.php
+++ b/app/src/Model/Proyecto/Broker/Contract/State.php
@@ -11,6 +11,16 @@ class State extends Common\Ideal\Model
public DateTimeInterface $date;
public State\Type $type;
+ public function isActive(): bool
+ {
+ return $this->type === State\Type::ACTIVE;
+ }
+ public function activate(): self
+ {
+ $this->type = State\Type::ACTIVE;
+ return $this;
+ }
+
protected function jsonComplement(): array
{
return [
diff --git a/app/src/Model/Venta/Datos.php b/app/src/Model/Venta/Datos.php
index 58f4db5..f0931c4 100644
--- a/app/src/Model/Venta/Datos.php
+++ b/app/src/Model/Venta/Datos.php
@@ -1,6 +1,7 @@
$this->profesion ?? '',
'direccion' => $this->direccion ?? '',
'telefono' => $this->telefono ?? '',
- 'email' => $this->email ?? ''
+ 'email' => $this->email ?? '',
+ 'fecha_nacimiento' => $this->fecha_nacimiento?->format('Y-m-d') ?? '',
];
}
}
diff --git a/app/src/Model/Venta/Promotion.php b/app/src/Model/Venta/Promotion.php
index 8a1cb25..49b9676 100644
--- a/app/src/Model/Venta/Promotion.php
+++ b/app/src/Model/Venta/Promotion.php
@@ -3,6 +3,7 @@ namespace Incoviba\Model\Venta;
use DateTimeInterface;
use Incoviba\Common;
+use Incoviba\Model\Proyecto;
use Incoviba\Model\Proyecto\Broker;
use Incoviba\Model\Venta\Promotion\State;
use Incoviba\Model\Venta\Promotion\Type;
@@ -61,13 +62,95 @@ class Promotion extends Common\Ideal\Model
return $this->units;
}
+ public function isActive(): bool
+ {
+ return $this->state === State::ACTIVE;
+ }
+ public function activate(): self
+ {
+ $this->state = State::ACTIVE;
+ return $this;
+ }
+
public function value(float $price): float
{
+ if (!$this->isActive()) {
+ return $price;
+ }
if ($this->type === Type::FIXED) {
return $price + $this->amount;
}
return $price / (1 - $this->amount);
}
+ public function inverse(float $price): float
+ {
+ if (!$this->isActive()) {
+ return $price;
+ }
+ if ($this->type === Type::FIXED) {
+ return $price - $this->amount;
+ }
+ return $price * (1 - $this->amount);
+ }
+
+ public function apply(Unidad $unit, float $price, ?Broker $broker = null): float
+ {
+ if (!$this->isActive()) {
+ return $price;
+ }
+ $projectIds = array_map(fn(Proyecto $proyecto) => $proyecto->id, $this->projects());
+ if (in_array($unit->proyectoTipoUnidad->proyecto->id, $projectIds)) {
+ return $this->value($price);
+ }
+ if ($broker !== null) {
+ $brokerIds = array_map(fn(Broker $broker) => $broker->id, $this->brokers());
+ if (in_array($broker->id, $brokerIds)) {
+ return $this->value($price);
+ }
+ }
+ $typeIds = array_map(fn(Proyecto\TipoUnidad $type) => $type->id, $this->unitTypes());
+ if (in_array($unit->proyectoTipoUnidad->tipoUnidad->id, $typeIds)) {
+ return $this->value($price);
+ }
+ $lineIds = array_map(fn(Proyecto\ProyectoTipoUnidad $line) => $line->id, $this->unitLines());
+ if (in_array($unit->proyectoTipoUnidad->id, $lineIds)) {
+ return $this->value($price);
+ }
+ $unitIds = array_map(fn(Unidad $unit) => $unit->id, $this->units());
+ if (in_array($unit->id, $unitIds)) {
+ return $this->value($price);
+ }
+ return $price;
+ }
+ public function reverse(Unidad $unit, float $price, ?Broker $broker = null): float
+ {
+ if (!$this->isActive()) {
+ return $price;
+ }
+ $projectIds = array_map(fn(Proyecto $proyecto) => $proyecto->id, $this->projects());
+ if (in_array($unit->proyectoTipoUnidad->proyecto->id, $projectIds)) {
+ return $this->inverse($price);
+ }
+ if ($broker !== null) {
+ $brokerIds = array_map(fn(Broker $broker) => $broker->id, $this->brokers());
+ if (in_array($broker->id, $brokerIds)) {
+ return $this->inverse($price);
+ }
+ }
+ $typeIds = array_map(fn(Proyecto\TipoUnidad $type) => $type->id, $this->unitTypes());
+ if (in_array($unit->proyectoTipoUnidad->tipoUnidad->id, $typeIds)) {
+ return $this->inverse($price);
+ }
+ $lineIds = array_map(fn(Proyecto\ProyectoTipoUnidad $line) => $line->id, $this->unitLines());
+ if (in_array($unit->proyectoTipoUnidad->id, $lineIds)) {
+ return $this->inverse($price);
+ }
+ $unitIds = array_map(fn(Unidad $unit) => $unit->id, $this->units());
+ if (in_array($unit->id, $unitIds)) {
+ return $this->inverse($price);
+ }
+ return $price;
+ }
protected function jsonComplement(): array
{
diff --git a/app/src/Model/Venta/Reservation.php b/app/src/Model/Venta/Reservation.php
index 3a94ebf..cc777eb 100644
--- a/app/src/Model/Venta/Reservation.php
+++ b/app/src/Model/Venta/Reservation.php
@@ -4,19 +4,53 @@ namespace Incoviba\Model\Venta;
use DateTimeInterface;
use Incoviba\Common;
use Incoviba\Model;
+use InvalidArgumentException;
class Reservation extends Common\Ideal\Model
{
+ public Model\Proyecto $project;
public Model\Persona $buyer;
public DateTimeInterface $date;
public array $units = [];
public array $promotions = [];
public ?Model\Proyecto\Broker $broker = null;
+
+ public function offer(): float
+ {
+ return array_sum(array_column($this->units, 'value'));
+ }
+ public function withCommission(): float
+ {
+ $base = 0;
+ foreach ($this->units as $unit) {
+ foreach ($this->promotions as $promotion) {
+ $base += $promotion->activate()->reverse($unit['unit'], $unit['value'], $this->broker);
+ }
+ }
+ return $base;
+ }
+ public function base(): float
+ {
+ $base = $this->withCommission();
+ if ($this->broker !== null) {
+ $base = $this->broker->reverseCommission($this->project, $base, $this->date);
+ }
+ return $base;
+ }
+ public function price(): float
+ {
+ $price = 0;
+ foreach ($this->units as $unit) {
+ $price += $unit->unit->precio($this->date)?->valor ?? 0;
+ }
+ return $price;
+ }
+
protected array $states = [];
public function states(): array
{
- if (!isset($this->states)) {
+ if (count($this->states) === 0) {
$this->states = $this->runFactory('states');
}
return $this->states;
@@ -27,7 +61,11 @@ class Reservation extends Common\Ideal\Model
public function currentState(): Model\Venta\Reservation\State
{
if (!isset($this->currentState)) {
- $this->currentState = last($this->states());
+ $states = $this->states();
+ if (count($states) === 0) {
+ throw new InvalidArgumentException('States must not be empty');
+ }
+ $this->currentState = last($states);
}
return $this->currentState;
}
@@ -35,16 +73,15 @@ class Reservation extends Common\Ideal\Model
public function addUnit(Model\Venta\Unidad $unit, float $value): self
{
if (($i = $this->findUnit($unit->id)) !== null) {
- $this->units[$i]['value'] = $value;
+ $this->units[$i]->value = $value;
return $this;
}
- $this->units[] = [
+ $this->units[] = (object) [
'unit' => $unit,
'value' => $value,
];
return $this;
}
-
public function removeUnit(int $unit_id): self
{
if (($i = $this->findUnit($unit_id)) === null) {
@@ -54,30 +91,47 @@ class Reservation extends Common\Ideal\Model
$this->units = array_values($this->units);
return $this;
}
-
public function findUnit(int $unit_id): ?int
{
- foreach ($this->units as $idx => $unit) {
- if ($unit['unit']->id == $unit_id) {
- return $idx;
- }
- }
- return null;
+ return array_find_key($this->units, fn($unit) => $unit->unit->id == $unit_id);
}
-
public function hasUnit(int $unit_id): bool
{
return $this->findUnit($unit_id) !== null;
}
+ public function summary(): string
+ {
+ $unitSummary = array_map(function($unit) {
+ $type = $unit->unit->proyectoTipoUnidad->tipoUnidad->descripcion;
+ $cap = strtoupper(strstr($type, 0, 1));
+ return "{$cap}{$unit->unit->descripcion}";
+ }, $this->units);
+ return implode('', $unitSummary);
+ }
+
+ public function valid(): bool
+ {
+ $base = $this->base();
+ $price = $this->price();
+ return $base >= $price;
+ }
+
protected function jsonComplement(): array
{
return [
- 'buyer_rut' => $this->buyer->rut,
+ 'project_id' => $this->project->id,
+ 'buyer' => $this->buyer,
'date' => $this->date->format('Y-m-d'),
'units' => $this->units,
'promotions' => $this->promotions,
- 'broker_rut' => $this->broker?->rut,
+ 'broker' => $this->broker,
+ 'offer' => $this->offer(),
+ 'with_commission' => $this->withCommission(),
+ 'base' => $this->base(),
+ 'price' => $this->price(),
+ 'valid' => $this->valid(),
+ 'summary' => $this->summary()
];
}
}
diff --git a/app/src/Model/Venta/Reservation/Detail/Type.php b/app/src/Model/Venta/Reservation/Detail/Type.php
new file mode 100644
index 0000000..4129449
--- /dev/null
+++ b/app/src/Model/Venta/Reservation/Detail/Type.php
@@ -0,0 +1,17 @@
+ $this->value,
+ 'description' => $this->name
+ ];
+ }
+}
diff --git a/app/src/Model/Venta/Reservation/State.php b/app/src/Model/Venta/Reservation/State.php
index a24771b..64eeed5 100644
--- a/app/src/Model/Venta/Reservation/State.php
+++ b/app/src/Model/Venta/Reservation/State.php
@@ -9,17 +9,14 @@ class State extends Common\Ideal\Model
{
public Model\Venta\Reservation $reservation;
public DateTimeInterface $date;
- public int $type;
+ public Model\Venta\Reservation\State\Type $type;
protected function jsonComplement(): array
{
return [
'reservation_id' => $this->reservation->id,
'date' => $this->date->format('Y-m-d'),
- 'type' => [
- 'id' => $this->type,
- 'description' => State\Type::name($this->type)
- ]
+ 'type' => $this->type
];
}
-}
\ No newline at end of file
+}
diff --git a/app/src/Model/Venta/Reservation/State/Type.php b/app/src/Model/Venta/Reservation/State/Type.php
index 464ec24..96d60e5 100644
--- a/app/src/Model/Venta/Reservation/State/Type.php
+++ b/app/src/Model/Venta/Reservation/State/Type.php
@@ -3,17 +3,21 @@ namespace Incoviba\Model\Venta\Reservation\State;
enum Type: int
{
- case ACTIVE = 1;
case INACTIVE = 0;
+ case ACTIVE = 1;
+ case PROMISED = 2;
case REJECTED = -1;
+ case CANCELLED = -2;
- public static function name(int $type): string
+ public function jsonSerialize(): array
{
- return match ($type) {
- self::ACTIVE => 'active',
- self::INACTIVE => 'inactive',
- self::REJECTED => 'rejected',
- default => throw new \InvalidArgumentException('Unexpected match value')
- };
+ return [
+ 'id' => $this->value,
+ 'description' => $this->name
+ ];
}
-}
\ No newline at end of file
+ public static function getTypes(): array
+ {
+ return [self::ACTIVE->value, self::INACTIVE->value, self::REJECTED->value];
+ }
+}
diff --git a/app/src/Repository/Persona/Datos.php b/app/src/Repository/Persona/Datos.php
index bfec12b..06cd4b7 100644
--- a/app/src/Repository/Persona/Datos.php
+++ b/app/src/Repository/Persona/Datos.php
@@ -29,6 +29,9 @@ class Datos extends Ideal\Repository
->register('direccion_id', (new Implement\Repository\Mapper())
->setProperty('direccion')
->setFunction(function($data) {
+ if ($data['direccion_id'] === null) {
+ return null;
+ }
return $this->direccionRepository->fetchById($data['direccion_id']);
})->setDefault(null))
->register('telefono', (new Implement\Repository\Mapper())->setFunction(function($data) {
@@ -56,7 +59,7 @@ class Datos extends Ideal\Repository
}
public function save(Define\Model $model): Model\Persona\Datos
{
- $this->saveNew([
+ $model->id = $this->saveNew([
'persona_rut', 'direccion_id', 'telefono', 'email', 'fecha_nacimiento', 'sexo', 'estado_civil',
'nacionalidad', 'ocupacion'
], [
@@ -113,4 +116,11 @@ class Datos extends Ideal\Repository
}
$this->connection->execute($query, $flattened);
}
+
+ public function filterData(array $data): array
+ {
+ $fields = ['persona_rut', 'direccion_id', 'telefono', 'email', 'fecha_nacimiento', 'sexo', 'estado_civil',
+ 'nacionalidad', 'ocupacion'];
+ return array_intersect_key($data, array_flip($fields));
+ }
}
diff --git a/app/src/Repository/Proyecto/Broker/Contract.php b/app/src/Repository/Proyecto/Broker/Contract.php
index 66d1bd5..221e74e 100644
--- a/app/src/Repository/Proyecto/Broker/Contract.php
+++ b/app/src/Repository/Proyecto/Broker/Contract.php
@@ -93,7 +93,7 @@ class Contract extends Common\Ideal\Repository
->select('a.*')
->from("{$this->getTable()} a")
->joined($this->statusJoin())
- ->where('a.broker_rut = :broker_rut AND bcs.state = :state');
+ ->where('a.broker_rut = :broker_rut AND bcs.type = :state');
return $this->fetchMany($query, ['broker_rut' => $brokerRut, 'state' => Model\Proyecto\Broker\Contract\Type::ACTIVE]);
}
@@ -108,8 +108,8 @@ class Contract extends Common\Ideal\Repository
->select('a.*')
->from("{$this->getTable()} a")
->joined($this->statusJoin())
- ->where('a.proyecto_id = :proyecto_id AND bcs.state = :state');
- return $this->fetchMany($query, ['proyecto_id' => $projectId, 'state' => Model\Proyecto\Broker\Contract\State\Type::ACTIVE->value]);
+ ->where('a.project_id = :project_id AND bcs.type = :state');
+ return $this->fetchMany($query, ['project_id' => $projectId, 'state' => Model\Proyecto\Broker\Contract\State\Type::ACTIVE->value]);
}
/**
diff --git a/app/src/Repository/Venta/EstadoPrecio.php b/app/src/Repository/Venta/EstadoPrecio.php
index 879ff05..231e1b4 100644
--- a/app/src/Repository/Venta/EstadoPrecio.php
+++ b/app/src/Repository/Venta/EstadoPrecio.php
@@ -54,8 +54,6 @@ class EstadoPrecio extends Ideal\Repository
public function fetchByPrecio(int $precio_id): array
{
$query = "SELECT * FROM `{$this->getTable()}` WHERE `precio` = ?";
- error_log($query.PHP_EOL,3,'/logs/query.log');
- error_log($precio_id.PHP_EOL,3,'/logs/query.log');
return $this->fetchMany($query, [$precio_id]);
}
diff --git a/app/src/Repository/Venta/Promotion.php b/app/src/Repository/Venta/Promotion.php
index 136b4aa..0b20bff 100644
--- a/app/src/Repository/Venta/Promotion.php
+++ b/app/src/Repository/Venta/Promotion.php
@@ -212,7 +212,7 @@ class Promotion extends Common\Ideal\Repository
->joined('LEFT OUTER JOIN proyecto_tipo_unidad ptu1 ON ptu.id = unidad.pt')
->where('(pp.project_id = :project_id OR put.project_id = :project_id OR ptu.proyecto = :project_id OR ptu1.proyecto = :project_id) AND a.state = :state')
->group('a.id');
- return $this->fetchMany($query, ['project_id' => $project_id, 'state' => Model\Venta\Promotion\State::ACTIVE]);
+ return $this->fetchMany($query, ['project_id' => $project_id, 'state' => Model\Venta\Promotion\State::ACTIVE->value]);
}
/**
diff --git a/app/src/Repository/Venta/Reservation.php b/app/src/Repository/Venta/Reservation.php
index 8ff13c7..45f005f 100644
--- a/app/src/Repository/Venta/Reservation.php
+++ b/app/src/Repository/Venta/Reservation.php
@@ -3,14 +3,19 @@ namespace Incoviba\Repository\Venta;
use DateTimeInterface;
use DateInterval;
+use Incoviba\Common\Define;
+use Incoviba\Exception\Model\InvalidState;
use PDO;
use Incoviba\Common;
use Incoviba\Model;
use Incoviba\Repository;
+use PDOException;
class Reservation extends Common\Ideal\Repository
{
- public function __construct(Common\Define\Connection $connection, protected Repository\Persona $personaRepository,
+ public function __construct(Common\Define\Connection $connection,
+ protected Repository\Proyecto $proyectoRepository,
+ protected Repository\Persona $personaRepository,
protected Repository\Proyecto\Broker $brokerRepository,
protected Unidad $unitRepository, protected Promotion $promotionRepository)
{
@@ -25,37 +30,35 @@ class Reservation extends Common\Ideal\Repository
public function create(?array $data = null): Model\Venta\Reservation
{
$map = (new Common\Implement\Repository\MapperParser())
+ ->register('project_id', (new Common\Implement\Repository\Mapper())
+ ->setProperty('project')
+ ->setFunction(function($data) {
+ return $this->proyectoRepository->fetchById($data['project_id']);
+ }))
->register('buyer_rut', (new Common\Implement\Repository\Mapper())
->setProperty('buyer')
- ->setFunction(function($data) use ($data) {
+ ->setFunction(function($data) {
return $this->personaRepository->fetchById($data['buyer_rut']);
}))
- ->register('date', new Common\Implement\Repository\Mapper\DateTime('date'))
- ->register('broker_rut', (new Common\Implement\Repository\Mapper())
- ->setProperty('broker')
- ->setDefault(null)
- ->setFunction(function($data) use ($data) {
- try {
- return $this->brokerRepository->fetchById($data['broker_rut']);
- } catch (Common\Implement\Exception\EmptyResult) {
- return null;
- }
- }));
+ ->register('date', new Common\Implement\Repository\Mapper\DateTime('date'));
return $this->parseData(new Model\Venta\Reservation(), $data, $map);
}
public function save(Common\Define\Model $model): Model\Venta\Reservation
{
- $model->id = $this->saveNew([
- 'buyer_rut',
- 'date',
- 'broker_rut'
- ], [
- $model->buyer->rut,
- $model->date->format('Y-m-d'),
- $model->broker?->rut
- ]);
+ if (!isset($model->id)) {
+ $model->id = $this->saveNew([
+ 'project_id',
+ 'buyer_rut',
+ 'date'
+ ], [
+ $model->project->id,
+ $model->buyer->rut,
+ $model->date->format('Y-m-d')
+ ]);
+ }
$this->saveUnits($model);
$this->savePromotions($model);
+ $this->saveBroker($model);
return $model;
}
@@ -67,15 +70,22 @@ class Reservation extends Common\Ideal\Repository
*/
public function edit(Common\Define\Model $model, array $new_data): Model\Venta\Reservation
{
- return $this->update($model, ['buyer_rut', 'date', 'broker_rut'], $new_data);
+ $model = $this->update($model, ['project_id', 'buyer_rut', 'date'], $new_data);
+ $this->editUnits($model, $new_data);
+ $this->editPromotions($model, $new_data);
+ $this->editBroker($model, $new_data);
+ return $model;
}
public function load(array $data_row): Model\Venta\Reservation
{
$model = parent::load($data_row);
- $this->fetchUnits($model);
- $this->fetchPromotions($model);
+ $this->fetchUnits($model, $data_row);
+ try {
+ $this->fetchBroker($model, $data_row);
+ } catch (Common\Implement\Exception\EmptyResult) {}
+ $this->fetchPromotions($model, $data_row);
return $model;
}
@@ -93,6 +103,88 @@ class Reservation extends Common\Ideal\Repository
->where('buyer_rut = :buyer_rut AND date >= :date');
return $this->fetchOne($query, ['buyer_rut' => $buyer_rut, 'date' => $date->sub(new DateInterval('P10D'))->format('Y-m-d')]);
}
+ public function fetchByProject(int $project_id): array
+ {
+ $query = $this->connection->getQueryBuilder()
+ ->select()
+ ->from('reservations')
+ ->where('project_id = :project_id');
+ return $this->fetchMany($query, ['project_id' => $project_id]);
+ }
+
+ /**
+ * @param int $project_id
+ * @param int $state
+ * @return array
+ * @throws Common\Implement\Exception\EmptyResult
+ * @throws InvalidState
+ */
+ public function fetchState(int $project_id, int $state): array
+ {
+ if (!in_array($state, Model\Venta\Reservation\State\Type::getTypes())) {
+ throw new InvalidState();
+ }
+ $sub1 = $this->connection->getQueryBuilder()
+ ->select('MAX(id) AS id, reservation_id')
+ ->from('reservation_states')
+ ->group('reservation_id');
+ $sub2 = $this->connection->getQueryBuilder()
+ ->select('er1.*')
+ ->from('reservation_states er1')
+ ->joined("INNER JOIN ({$sub1}) er0 ON er0.id = er1.id");
+
+ $query = $this->connection->getQueryBuilder()
+ ->select('a.*')
+ ->from("{$this->getTable()} a")
+ ->joined("INNER JOIN ({$sub2}) er ON er.reservation_id = a.id")
+ ->where('a.project_id = :project_id AND er.type = :state');
+ return $this->fetchMany($query, ['project_id' => $project_id,
+ 'state' => $state]);
+ }
+ /**
+ * @param int $project_id
+ * @return array
+ * @throws Common\Implement\Exception\EmptyResult
+ */
+ public function fetchActive(int $project_id): array
+ {
+ try {
+ return $this->fetchState($project_id, Model\Venta\Reservation\State\Type::ACTIVE->value);
+ } catch (InvalidState $exception) {
+ throw new Common\Implement\Exception\EmptyResult('Select active reservations', $exception);
+ }
+ }
+
+ /**
+ * @param int $project_id
+ * @return array
+ * @throws Common\Implement\Exception\EmptyResult
+ */
+ public function fetchPending(int $project_id): array
+ {
+ try {
+ return $this->fetchState($project_id, Model\Venta\Reservation\State\Type::INACTIVE->value);
+ } catch (InvalidState $exception) {
+ throw new Common\Implement\Exception\EmptyResult('Select pending reservations', $exception);
+ }
+ }
+
+ /**
+ * @param int $project_id
+ * @return array
+ * @throws Common\Implement\Exception\EmptyResult
+ */
+ public function fetchRejected(int $project_id): array
+ {
+ try {
+ return [
+ ...$this->fetchState($project_id, Model\Venta\Reservation\State\Type::REJECTED->value),
+ ...$this->fetchState($project_id, Model\Venta\Reservation\State\Type::CANCELLED->value)
+ ];
+ } catch (InvalidState $exception) {
+ throw new Common\Implement\Exception\EmptyResult('Select rejected reservations', $exception);
+ }
+ }
protected function saveUnits(Model\Venta\Reservation $reservation): void
{
@@ -101,22 +193,74 @@ class Reservation extends Common\Ideal\Repository
}
$queryCheck = $this->connection->getQueryBuilder()
->select('COUNT(id) AS cnt')
- ->from('reservation_data')
- ->where('reservation_id = :id AND type = "Unit" AND reference_id = :unit_id');
+ ->from('reservation_details')
+ ->where('reservation_id = :id AND type = :type AND reference_id = :unit_id');
$statementCheck = $this->connection->prepare($queryCheck);
$queryInsert = $this->connection->getQueryBuilder()
->insert()
- ->into('reservation_data')
+ ->into('reservation_details')
->columns(['reservation_id', 'type', 'reference_id', 'value'])
->values([':reservation_id', ':type', ':reference_id', ':value']);
$statementInsert = $this->connection->prepare($queryInsert);
foreach ($reservation->units as $unit) {
- $statementCheck->execute(['id' => $reservation->id, 'unit_id' => $unit['unit']->id]);
+ $statementCheck->execute([
+ 'id' => $reservation->id,
+ 'type' => Model\Venta\Reservation\Detail\Type::Unit->value,
+ 'unit_id' => $unit->unit->id
+ ]);
$result = $statementCheck->fetch(PDO::FETCH_ASSOC);
if ($result['cnt'] > 0) {
continue;
}
- $statementInsert->execute(['reservation_id' => $reservation->id, 'type' => 'Unit', 'reference_id' => $unit['unit']->id, 'value' => $unit['value']]);
+ $statementInsert->execute([
+ 'reservation_id' => $reservation->id,
+ 'type' => Model\Venta\Reservation\Detail\Type::Unit->value,
+ 'reference_id' => $unit->unit->id,
+ 'value' => $unit->value
+ ]);
+ }
+
+ $this->cleanUpUnits($reservation);
+ }
+ protected function cleanUpUnits(Model\Venta\Reservation $reservation): void
+ {
+ $this->cleanUpDetails($reservation,
+ Model\Venta\Reservation\Detail\Type::Unit->value,
+ array_map(fn($unit) => $unit->unit->id, $reservation->units));
+ }
+ protected function saveBroker(Model\Venta\Reservation &$reservation): void
+ {
+ if ($reservation->broker === null) {
+ $this->removeBroker($reservation);
+ return;
+ }
+ try {
+ $queryCheck = $this->connection->getQueryBuilder()
+ ->select('reference_id')
+ ->from('reservation_details')
+ ->where('reservation_id = :id AND type = :type');
+ $statementCheck = $this->connection->execute($queryCheck, [
+ 'id' => $reservation->id,
+ 'type' => Model\Venta\Reservation\Detail\Type::Broker->value
+ ]);
+ $result = $statementCheck->fetch(PDO::FETCH_ASSOC);
+ if ($result === false) {
+ throw new PDOException();
+ }
+ $new_id = $reservation->broker->rut;
+ $reservation->broker = $this->brokerRepository->fetchById($result['reference_id']);
+ $this->editBroker($reservation, ['broker_rut' => $new_id]);
+ } catch (PDOException) {
+ $queryInsert = $this->connection->getQueryBuilder()
+ ->insert()
+ ->into('reservation_details')
+ ->columns(['reservation_id', 'type', 'reference_id'])
+ ->values([':reservation_id', ':type', ':reference_id']);
+ $this->connection->execute($queryInsert, [
+ 'reservation_id' => $reservation->id,
+ 'type' => Model\Venta\Reservation\Detail\Type::Broker->value,
+ 'reference_id' => $reservation->broker->rut
+ ]);
}
}
protected function savePromotions(Model\Venta\Reservation $reservation): void
@@ -126,60 +270,152 @@ class Reservation extends Common\Ideal\Repository
}
$queryCheck = $this->connection->getQueryBuilder()
->select('COUNT(id) AS cnt')
- ->from('reservation_data')
- ->where('reservation_id = :id AND type = "Promotion" AND reference_id = :promotion_id');
+ ->from('reservation_details')
+ ->where('reservation_id = :id AND type = :type AND reference_id = :promotion_id');
$statementCheck = $this->connection->prepare($queryCheck);
$queryInsert = $this->connection->getQueryBuilder()
->insert()
- ->into('reservation_data')
+ ->into('reservation_details')
->columns(['reservation_id', 'type', 'reference_id'])
->values([':reservation_id', ':type', ':reference_id']);
$statementInsert = $this->connection->prepare($queryInsert);
foreach ($reservation->promotions as $promotion) {
- $statementCheck->execute(['id' => $reservation->id, 'promotion_id' => $promotion->id]);
+ $statementCheck->execute([
+ 'id' => $reservation->id,
+ 'type' => Model\Venta\Reservation\Detail\Type::Promotion->value,
+ 'promotion_id' => $promotion->id
+ ]);
$result = $statementCheck->fetch(PDO::FETCH_ASSOC);
if ($result['cnt'] > 0) {
continue;
}
- $statementInsert->execute(['reservation_id' => $reservation->id, 'type' => 'Promotion', 'reference_id' => $promotion->id]);
+ $statementInsert->execute([
+ 'reservation_id' => $reservation->id,
+ 'type' => Model\Venta\Reservation\Detail\Type::Promotion->value,
+ 'reference_id' => $promotion->id
+ ]);
}
+
+ $this->cleanUpPromotions($reservation);
}
- protected function editUnits(Model\Venta\Reservation $reservation, array $new_data): void
+ protected function cleanUpPromotions(Model\Venta\Reservation $reservation): void
+ {
+ $this->cleanUpDetails($reservation,
+ Model\Venta\Reservation\Detail\Type::Promotion->value,
+ array_map(fn($promotion) => $promotion->id, $reservation->promotions));
+ }
+ protected function cleanUpDetails(Model\Venta\Reservation $reservation, int $type_id, array $currentIds): void
+ {
+ $queryCheck = $this->connection->getQueryBuilder()
+ ->select('COUNT(id) AS cnt')
+ ->from('reservation_details')
+ ->where('reservation_id = :id AND type = :type');
+ $statementCheck = $this->connection->prepare($queryCheck);
+ $deleteParam = implode(', ', array_map(fn($id) => ":id$id", $currentIds));
+ $queryDelete = $this->connection->getQueryBuilder()
+ ->delete()
+ ->from('reservation_details')
+ ->where("reservation_id = :id AND type = :type AND reference_id NOT IN ({$deleteParam})");
+ $statementDelete = $this->connection->prepare($queryDelete);
+
+ try {
+ $statementCheck->execute([
+ 'id' => $reservation->id,
+ 'type' => $type_id
+ ]);
+ $result = $statementCheck->fetch(PDO::FETCH_ASSOC);
+ if ($result['cnt'] <= count($currentIds)) {
+ return;
+ }
+ $deleteIdValues = array_combine(array_map(fn($id) => "id$id", $currentIds), $currentIds);
+ $statementDelete->execute(array_merge(
+ ['id' => $reservation->id, 'type' => $type_id],
+ $deleteIdValues));
+ } catch (PDOException) {}
+ }
+
+ protected function editUnits(Model\Venta\Reservation &$reservation, array $new_data): void
{
$querySelect = $this->connection->getQueryBuilder()
->select()
- ->from('reservation_data')
- ->where('reservation_id = :id AND type = "Unit" AND reference_id = :unit_id');
+ ->from('reservation_details')
+ ->where('reservation_id = :id AND type = :type AND reference_id = :unit_id');
$statementSelect = $this->connection->prepare($querySelect);
$queryUpdate = $this->connection->getQueryBuilder()
- ->update('reservation_data')
+ ->update('reservation_details')
->set('value = :value')
- ->where('reservation_id = :id AND type = "Unit" AND reference_id = :unit_id');
+ ->where('reservation_id = :id AND type = :type AND reference_id = :unit_id');
$statementUpdate = $this->connection->prepare($queryUpdate);
- foreach ($new_data as $unit_id => $value) {
- $idx = $reservation->findUnit($unit_id);
+ $queryInsert = $this->connection->getQueryBuilder()
+ ->insert()
+ ->into('reservation_details')
+ ->columns(['reservation_id', 'type', 'reference_id', 'value'])
+ ->values([':reservation_id', ':type', ':reference_id', ':value']);
+ $statementInsert = $this->connection->prepare($queryInsert);
+ foreach ($new_data['units'] as $unit) {
+ $idx = $reservation->findUnit($unit['unit_id']);
if ($idx === null) {
- $reservation->addUnit($this->unitRepository->fetchById($unit_id), $value);
+ $reservation->addUnit($this->unitRepository->fetchById($unit['unit_id']), $unit['value']);
+ $statementInsert->execute([
+ 'reservation_id' => $reservation->id,
+ 'type' => Model\Venta\Reservation\Detail\Type::Unit->value,
+ 'reference_id' => $unit['unit_id'],
+ 'value' => $unit['value']
+ ]);
continue;
}
- $statementSelect->execute(['id' => $reservation->id, 'unit_id' => $unit_id]);
+ $statementSelect->execute([
+ 'id' => $reservation->id,
+ 'type' => Model\Venta\Reservation\Detail\Type::Unit->value,
+ 'unit_id' => $unit['unit_id']
+ ]);
$result = $statementSelect->fetch(PDO::FETCH_ASSOC);
if (!$result) {
+ $reservation->addUnit($this->unitRepository->fetchById($unit['unit_id']), $unit['value']);
+ $statementInsert->execute([
+ 'reservation_id' => $reservation->id,
+ 'type' => Model\Venta\Reservation\Detail\Type::Unit->value,
+ 'reference_id' => $unit['unit_id'],
+ 'value' => $unit['value']
+ ]);
continue;
}
- $statementUpdate->execute(['id' => $reservation->id, 'unit_id' => $unit_id, 'value' => $value]);
- $reservation->units[$idx]['value'] = $value;
+ $statementUpdate->execute([
+ 'id' => $reservation->id,
+ 'type' => Model\Venta\Reservation\Detail\Type::Unit->value,
+ 'unit_id' => $unit['unit_id'],
+ 'value' => $unit['value']
+ ]);
+ $reservation->units[$idx]['value'] = $unit['value'];
}
}
- protected function editPromotions(Model\Venta\Reservation $reservation, array $new_data): void
+ protected function editBroker(Model\Venta\Reservation &$reservation, array $new_data): void
+ {
+ if (!array_key_exists('broker_rut', $new_data) or $new_data['broker_rut'] === $reservation->broker->rut) {
+ return;
+ }
+ try {
+ $query = $this->connection->getQueryBuilder()
+ ->update('reservation_details')
+ ->set('reference_id = :broker_rut')
+ ->where('reservation_id = :id AND type = :type');
+ $this->connection->execute($query, [
+ 'id' => $reservation->id,
+ 'type' => Model\Venta\Reservation\Detail\Type::Broker->value,
+ 'broker_rut' => $new_data['broker_rut']
+ ]);
+ $reservation->broker = $this->brokerRepository->fetchById($new_data['broker_rut']);
+ } catch (PDOException) {}
+ }
+ protected function editPromotions(Model\Venta\Reservation &$reservation, array $new_data): void
{
$querySelect = $this->connection->getQueryBuilder()
->select()
- ->from('reservation_data')
+ ->from('reservation_details')
->where('reservation_id = :id AND type = "Promotion" AND reference_id = :promotion_id');
$statementSelect = $this->connection->prepare($querySelect);
$queryUpdate = $this->connection->getQueryBuilder()
- ->update('reservation_data')
+ ->update('reservation_details')
->set('value = :value')
->where('reservation_id = :id AND type = "Promotion" AND reference_id = :promotion_id');
$statementUpdate = $this->connection->prepare($queryUpdate);
@@ -198,13 +434,26 @@ class Reservation extends Common\Ideal\Repository
$reservation->promotions[$idx] = $this->promotionRepository->fetchById($promotion_id);
}
}
- protected function fetchUnits(Model\Venta\Reservation &$reservation): Model\Venta\Reservation
+
+ protected function fetchUnits(Model\Venta\Reservation &$reservation, array $new_data): Model\Venta\Reservation
+ {
+ $this->fetchSavedUnits($reservation);
+
+ if (array_key_exists('units', $new_data) and count($new_data['units']) > 0) {
+ $this->fetchUnsavedUnits($reservation, $new_data);
+ }
+ return $reservation;
+ }
+ protected function fetchSavedUnits(Model\Venta\Reservation &$reservation): Model\Venta\Reservation
{
$query = $this->connection->getQueryBuilder()
->select()
- ->from('reservation_data')
- ->where('reservation_id = :id AND type = "Unit"');
- $statement = $this->connection->execute($query, ['id' => $reservation->id]);
+ ->from('reservation_details')
+ ->where('reservation_id = :id AND type = :type');
+ $statement = $this->connection->execute($query, [
+ 'id' => $reservation->id,
+ 'type' =>Model\Venta\Reservation\Detail\Type::Unit->value
+ ]);
while ($result = $statement->fetch(PDO::FETCH_ASSOC)) {
try {
@@ -213,13 +462,79 @@ class Reservation extends Common\Ideal\Repository
}
return $reservation;
}
- protected function fetchPromotions(Model\Venta\Reservation $reservation): Model\Venta\Reservation
+ protected function fetchUnsavedUnits(Model\Venta\Reservation &$reservation, array $new_data): Model\Venta\Reservation
+ {
+ if (!array_key_exists('units', $new_data) or count($new_data['units']) > 0) {
+ return $reservation;
+ }
+ $queryCheck = $this->connection->getQueryBuilder()
+ ->select('COUNT(id) AS cnt')
+ ->from('reservation_details')
+ ->where('reservation_id = :id AND type = :type AND reference_id = :unit_id');
+ $statementCheck = $this->connection->prepare($queryCheck);
+ foreach ($new_data['units'] as $unit) {
+ $statementCheck->execute([
+ 'id' => $reservation->id,
+ 'type' => Model\Venta\Reservation\Detail\Type::Unit->value,
+ 'unit_id' => $unit['unit_id']
+ ]);
+ $result = $statementCheck->fetch(PDO::FETCH_ASSOC);
+ if ($result['cnt'] > 0) {
+ continue;
+ }
+ try {
+ $reservation->addUnit($this->unitRepository->fetchById($unit['unit_id']), $unit['value']);
+ } catch (Common\Implement\Exception\EmptyResult) {}
+ }
+ return $reservation;
+ }
+
+ /**
+ * @param Model\Venta\Reservation $reservation
+ * @param array $new_data
+ * @return Model\Venta\Reservation
+ * @throws Common\Implement\Exception\EmptyResult
+ */
+ protected function fetchBroker(Model\Venta\Reservation &$reservation, array $new_data): Model\Venta\Reservation
+ {
+ if (!array_key_exists('broker_id', $new_data)) {
+ $query = $this->connection->getQueryBuilder()
+ ->select('reference_id')
+ ->from('reservation_details')
+ ->where('reservation_id = :id AND type = :type');
+ try {
+ $statement =$this->connection->execute($query, [
+ 'id' => $reservation->id,
+ 'type' => Model\Venta\Reservation\Detail\Type::Broker->value
+ ]);
+ $result = $statement->fetch(PDO::FETCH_ASSOC);
+ if ($result === false) {
+ throw new Common\Implement\Exception\EmptyResult($query);
+ }
+ $reservation->broker = $this->brokerRepository->fetchById($result['reference_id']);
+ } catch (PDOException) {}
+
+ return $reservation;
+ }
+ try {
+ $reservation->broker = $this->brokerRepository->fetchById($new_data['broker_id']);
+ } catch (Common\Implement\Exception\EmptyResult) {}
+ return $reservation;
+ }
+ protected function fetchPromotions(Model\Venta\Reservation &$reservation, array $new_data): Model\Venta\Reservation
+ {
+ $this->fetchSavedPromotions($reservation);
+ $this->fetchUnsavedPromotions($reservation, $new_data);
+ return $reservation;
+ }
+ protected function fetchSavedPromotions(Model\Venta\Reservation &$reservation): Model\Venta\Reservation
{
$query = $this->connection->getQueryBuilder()
->select()
- ->from('reservation_data')
- ->where('type = "Promotion" AND reservation_id = :id');
- $statement = $this->connection->execute($query, ['id' => $reservation->id]);
+ ->from('reservation_details')
+ ->where('type = :type AND reservation_id = :id');
+ $statement = $this->connection->execute($query,
+ ['id' => $reservation->id, 'type' => Model\Venta\Reservation\Detail\Type::Promotion->value]);
while ($result = $statement->fetch(PDO::FETCH_ASSOC)) {
try {
$reservation->promotions []= $this->promotionRepository->fetchById($result['reference_id']);
@@ -227,4 +542,43 @@ class Reservation extends Common\Ideal\Repository
}
return $reservation;
}
+ protected function fetchUnsavedPromotions(Model\Venta\Reservation &$reservation, array $new_data): Model\Venta\Reservation
+ {
+ if (!array_key_exists('promotions', $new_data) or count($new_data['promotions']) > 0) {
+ return $reservation;
+ }
+ $queryCheck = $this->connection->getQueryBuilder()
+ ->select('COUNT(id) AS cnt')
+ ->from('reservation_details')
+ ->where('type = :type AND reservation_id = :id AND reference_id = :promotion_id');
+ $statementCheck = $this->connection->prepare($queryCheck);
+ foreach ($new_data['promotions'] as $promotion) {
+ $statementCheck->execute([
+ 'id' => $reservation->id,
+ 'promotion_id' => $promotion
+ ]);
+ $result = $statementCheck->fetch(PDO::FETCH_ASSOC);
+ if ($result['cnt'] > 0) {
+ continue;
+ }
+ try {
+ $reservation->promotions []= $this->promotionRepository->fetchById($promotion);
+ } catch (Common\Implement\Exception\EmptyResult) {}
+ }
+ return $reservation;
+ }
+ protected function removeBroker(Model\Venta\Reservation &$reservation): void
+ {
+ try {
+ $query = $this->connection->getQueryBuilder()
+ ->delete()
+ ->from('reservation_details')
+ ->where('reservation_id = :id AND type = :type');
+ $this->connection->execute($query, [
+ 'id' => $reservation->id,
+ 'type' => Model\Venta\Reservation\Detail\Type::Broker->value
+ ]);
+ $reservation->broker = null;
+ } catch (PDOException) {}
+ }
}
diff --git a/app/src/Repository/Venta/Reservation/State.php b/app/src/Repository/Venta/Reservation/State.php
index 0a98a6d..841a849 100644
--- a/app/src/Repository/Venta/Reservation/State.php
+++ b/app/src/Repository/Venta/Reservation/State.php
@@ -7,7 +7,8 @@ use Incoviba\Repository;
class State extends Common\Ideal\Repository
{
- public function __construct(Common\Define\Connection $connection, protected Repository\Venta\Reservation $reservationRepository)
+ public function __construct(Common\Define\Connection $connection,
+ protected Repository\Venta\Reservation $reservationRepository)
{
parent::__construct($connection);
}
@@ -19,12 +20,16 @@ class State extends Common\Ideal\Repository
public function create(?array $data = null): Model\Venta\Reservation\State
{
- $map = (new Common\Implement\Repository\MapperParser(['type']))
+ $map = (new Common\Implement\Repository\MapperParser())
->register('reservation_id', (new Common\Implement\Repository\Mapper())
->setProperty('reservation')
- ->setFunction(function($data) use ($data) {
+ ->setFunction(function($data) {
return $this->reservationRepository->fetchById($data['reservation_id']);
}))
+ ->register('type', (new Common\Implement\Repository\Mapper())
+ ->setFunction(function($data) {
+ return Model\Venta\Reservation\State\Type::from($data['type']);
+ }))
->register('date', new Common\Implement\Repository\Mapper\DateTime('date'));
return $this->parseData(new Model\Venta\Reservation\State(), $data, $map);
}
@@ -32,7 +37,7 @@ class State extends Common\Ideal\Repository
{
$model->id = $this->saveNew(
['reservation_id', 'date', 'type'],
- [$model->reservation->id, $model->date->format('Y-m-d'), $model->type]
+ [$model->reservation->id, $model->date->format('Y-m-d'), $model->type->value]
);
return $model;
}
diff --git a/app/src/Service/Direccion.php b/app/src/Service/Direccion.php
new file mode 100644
index 0000000..7113654
--- /dev/null
+++ b/app/src/Service/Direccion.php
@@ -0,0 +1,49 @@
+ 'calle',
+ 'number' => 'numero',
+ 'comuna_id' => 'comuna',
+ ];
+ foreach ($data as $key => $value) {
+ if (array_key_exists($key, $dataMap)) {
+ $data[$dataMap[$key]] = $value;
+ unset($data[$key]);
+ }
+ }
+ try {
+ return $this->direccionRepository->fetchByCalleAndNumeroAndExtraAndComuna($data['calle'], $data['numero'], $data['extra'], $data['comuna']);
+ } catch (Implement\Exception\EmptyResult) {
+ $filteredData = $this->direccionRepository->filterData($data);
+ $direccion = $this->direccionRepository->create($filteredData);
+ try {
+ return $this->direccionRepository->save($direccion);
+ } catch (PDOException $exception) {
+ throw new ServiceAction\Create(__CLASS__, $exception);
+ }
+ }
+ }
+}
diff --git a/app/src/Service/Persona.php b/app/src/Service/Persona.php
index bfabeca..e41a8a6 100644
--- a/app/src/Service/Persona.php
+++ b/app/src/Service/Persona.php
@@ -15,7 +15,8 @@ class Persona extends Ideal\Service
public function __construct(LoggerInterface $logger,
protected Repository\Persona $personaRepository,
protected Repository\Persona\Datos $datosPersonaRepository,
- protected Repository\Venta\Propietario $propietarioRepository)
+ protected Repository\Venta\Propietario $propietarioRepository,
+ protected Direccion $direccionService)
{
parent::__construct($logger);
}
@@ -35,7 +36,7 @@ class Persona extends Ideal\Service
/**
* @param int $rut
* @return Model\Persona
- * @throws Read|Create
+ * @throws Read
*/
public function getById(int $rut): Model\Persona
{
@@ -44,7 +45,11 @@ class Persona extends Ideal\Service
} catch (Implement\Exception\EmptyResult) {
try {
$this->propietarioRepository->fetchById($rut);
- return $this->add(compact('rut'));
+ try {
+ return $this->add(compact('rut'));
+ } catch (Create $exception) {
+ throw new Read(__CLASS__, $exception);
+ }
} catch (Implement\Exception\EmptyResult $exception) {
throw new Read(__CLASS__, $exception);
}
@@ -63,44 +68,34 @@ class Persona extends Ideal\Service
} catch (Implement\Exception\EmptyResult) {
try {
$propietario = $this->propietarioRepository->fetchById($data['rut']);
- } catch (Implement\Exception\EmptyResult $exception) {
- throw new Create(__CLASS__, $exception);
- }
- $data['rut'] = $propietario->rut;
- $data['digito'] = $propietario->dv;
- $data['nombres'] = $propietario->nombres;
- $data['apellido_paterno'] = $propietario->apellidos['paterno'];
- $data['apellido_materno'] = $propietario->apellidos['materno'] ?? '';
- $persona = $this->personaRepository->create($data);
- try {
- $persona = $this->personaRepository->save($persona);
- } catch (PDOException $exception) {
- throw new Create(__CLASS__, $exception);
- }
- }
- 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'];
- }
- if (isset($data['telefono'])) {
- $datosData['telefono'] = $data['telefono'];
- }
- try {
- $datos = $this->datosPersonaRepository->fetchByPersona($persona->rut);
- $this->datosPersonaRepository->edit($datos, $data);
+ $persona = $this->addFromPropietario($propietario);
} catch (Implement\Exception\EmptyResult) {
- $datos = $this->datosPersonaRepository->create($datosData);
+ $dataMap = [
+ 'digit' => 'digito',
+ 'name' => 'nombres',
+ 'names' => 'nombres',
+ 'last_name' => 'apellido_paterno',
+ 'last_name2' => 'apellido_materno',
+ ];
+ foreach ($data as $key => $value) {
+ if (array_key_exists($key, $dataMap)) {
+ $data[$dataMap[$key]] = $value;
+ unset($data[$key]);
+ }
+ }
+
+ $filteredData = $this->personaRepository->filterData($data);
try {
- $this->datosPersonaRepository->save($datos);
+ $persona = $this->personaRepository->create($filteredData);
+ $persona = $this->personaRepository->save($persona);
} catch (PDOException $exception) {
throw new Create(__CLASS__, $exception);
}
}
+
}
+ $this->addDatos($persona, $data);
+
return $this->process($persona);
}
@@ -176,4 +171,113 @@ class Persona extends Ideal\Service
->setArgs(['persona_rut' => $persona->rut]));
return $persona;
}
+ /**
+ * @param Model\Venta\Propietario $propietario
+ * @return Model\Persona
+ * @throws Create
+ */
+ protected function addFromPropietario(Model\Venta\Propietario $propietario): Model\Persona
+ {
+ $data = [
+ 'rut' => $propietario->rut,
+ 'digito' => $propietario->dv,
+ 'nombres' => $propietario->nombres,
+ 'apellido_paterno' => $propietario->apellidos['paterno'],
+ 'apellido_materno' => $propietario->apellidos['materno'] ?? '',
+ ];
+ try {
+ $persona = $this->personaRepository->create($data);
+ $persona = $this->personaRepository->save($persona);
+ } catch (PDOException $exception) {
+ throw new Create(__CLASS__, $exception);
+ }
+
+ $datosData = [];
+ if ($propietario->datos->direccion) {
+ $datosData['direccion_id'] = $propietario->datos?->direccion->id;
+ }
+ if ($propietario->datos->email) {
+ $datosData['email'] = $propietario->datos->email;
+ }
+ if ($propietario->datos->telefono) {
+ $datosData['telefono'] = $propietario->datos->telefono;
+ }
+ if ($propietario->datos->estado_civil) {
+ $datosData['estado_civil'] = $propietario->datos->estado_civil;
+ }
+ if ($propietario->datos->fecha_nacimiento) {
+ $datosData['fecha_nacimiento'] = $propietario->datos->fecha_nacimiento;
+ }
+ if ($propietario->datos->profesion) {
+ $datosData['ocupacion'] = $propietario->datos->profesion;
+ }
+ if ($propietario->datos->sexo) {
+ $datosData['sexo'] = $propietario->datos->sexo;
+ }
+
+ $this->addDatos($persona, $datosData);
+ return $persona;
+ }
+
+ /**
+ * @param Model\Persona $persona
+ * @param array $data
+ * @return Model\Persona
+ * @throws Create
+ */
+ protected function addDatos(Model\Persona $persona, array $data): Model\Persona
+ {
+ $addressData = [];
+ foreach ($data as $key => $value) {
+ if (!str_starts_with($key, 'address_') and !str_starts_with($key, 'direccion_')) {
+ continue;
+ }
+ if (str_starts_with($key, 'direccion_')) {
+ $newKey = substr($key, strlen('direccion_'));
+ } else {
+ $newKey = substr($key, strlen('address_'));
+ }
+ $addressData[$newKey] = $value;
+ }
+ if (!empty($addressData)) {
+ $address = $this->direccionService->add($addressData);
+ foreach ($data as $key => $value) {
+ if (str_starts_with($key, 'address_') or str_starts_with($key, 'direccion_')) {
+ unset($data[$key]);
+ }
+ }
+ $data['direccion_id'] = $address->id;
+ }
+
+ $dataMap = [
+ 'phone' => 'telefono',
+ 'profession' => 'ocupacion',
+ 'profesion' => 'ocupacion',
+ 'sex' => 'sexo',
+ 'marital_status' => 'estado_civil',
+ 'birth_date' => 'fecha_nacimiento',
+ 'birthdate' => 'fecha_nacimiento',
+ ];
+ foreach ($data as $key => $value) {
+ if (array_key_exists($key, $dataMap)) {
+ $data[$dataMap[$key]] = $value;
+ unset($data[$key]);
+ }
+ }
+ try {
+ $datos = $this->datosPersonaRepository->fetchByPersona($persona->rut);
+ $this->datosPersonaRepository->edit($datos, $data);
+ } catch (Implement\Exception\EmptyResult $exception) {
+ $datosData = ['persona_rut' => $persona->rut, ...$data];
+ $datosData = $this->datosPersonaRepository->filterData($datosData);
+ $datos = $this->datosPersonaRepository->create($datosData);
+ try {
+ $this->datosPersonaRepository->save($datos);
+ } catch (PDOException $exception) {
+ throw new Create(__CLASS__, $exception);
+ }
+ }
+
+ return $persona;
+ }
}
diff --git a/app/src/Service/Venta/Promotion.php b/app/src/Service/Venta/Promotion.php
index 6dc0194..052be9b 100644
--- a/app/src/Service/Venta/Promotion.php
+++ b/app/src/Service/Venta/Promotion.php
@@ -48,6 +48,20 @@ class Promotion extends Ideal\Service
}
}
+ /**
+ * @param int $project_id
+ * @return array
+ * @throws Exception\ServiceAction\Read
+ */
+ public function getByProject(int $project_id): array
+ {
+ try {
+ return array_map([$this, 'process'], $this->promotionRepository->fetchByProject($project_id));
+ } catch (Implement\Exception\EmptyResult $exception) {
+ throw new Exception\ServiceAction\Read(__CLASS__, $exception);
+ }
+ }
+
/**
* @param int $contract_id
* @return array
diff --git a/app/src/Service/Venta/Reservation.php b/app/src/Service/Venta/Reservation.php
index 9ceca60..a12f442 100644
--- a/app/src/Service/Venta/Reservation.php
+++ b/app/src/Service/Venta/Reservation.php
@@ -1,8 +1,10 @@
reservationRepository->fetchAll($order);
+ return array_map([$this, 'process'], $this->reservationRepository->fetchAll($order));
} catch (Implement\Exception\EmptyResult) {
return [];
}
}
+ /**
+ * @param int $project_id
+ * @return array
+ * @throws ServiceAction\Read
+ */
+ public function getByProject(int $project_id): array
+ {
+ try {
+ return array_map([$this, 'process'], $this->reservationRepository->fetchByProject($project_id));
+ } catch (Implement\Exception\EmptyResult $exception) {
+ throw new ServiceAction\Read(__CLASS__, $exception);
+ }
+ }
+
public function get(int $id): Model\Venta\Reservation
{
try {
@@ -37,25 +59,131 @@ class Reservation extends Ideal\Service\API
}
}
- public function add(array $data): Model\Venta\Reservation
+ /**
+ * @param int $buyer_rut
+ * @param DateTimeInterface $date
+ * @return Model\Venta\Reservation
+ * @throws Read
+ */
+ public function getByBuyerAndDate(int $buyer_rut, DateTimeInterface $date): Model\Venta\Reservation
{
try {
- $date = new DateTimeImmutable();
- try {
- $date = new DateTimeImmutable($data['date']);
- } catch (DateMalformedStringException) {}
- return $this->process($this->reservationRepository->fetchByBuyerAndDate($data['buyer_rut'], $date));
- } catch (Implement\Exception\EmptyResult) {}
-
- try {
- $reservationData = $this->reservationRepository->filterData($data);
- $reservation = $this->reservationRepository->create($reservationData);
- $this->reservationRepository->save($reservation);
- return $this->process($reservation);
- } catch (PDOException $exception) {
- throw new ServiceAction\Create(__CLASS__, $exception);
+ return $this->process($this->reservationRepository->fetchByBuyerAndDate($buyer_rut, $date));
+ } catch (Implement\Exception\EmptyResult $exception) {
+ throw new ServiceAction\Read(__CLASS__, $exception);
}
}
+
+ /**
+ * @param int $project_id
+ * @return array
+ * @throws ServiceAction\Read
+ */
+ public function getActive(int $project_id): array
+ {
+ try {
+ return array_map([$this, 'process'], $this->reservationRepository->fetchActive($project_id));
+ } catch (Implement\Exception\EmptyResult $exception) {
+ throw new ServiceAction\Read(__CLASS__, $exception);
+ }
+ }
+
+ /**
+ * @param int $project_id
+ * @return array
+ * @throws ServiceAction\Read
+ */
+ public function getPending(int $project_id): array
+ {
+ try {
+ return array_map([$this, 'process'], $this->reservationRepository->fetchPending($project_id));
+ } catch (Implement\Exception\EmptyResult $exception) {
+ throw new ServiceAction\Read(__CLASS__, $exception);
+ }
+ }
+
+ /**
+ * @param int $project_id
+ * @return array
+ * @throws ServiceAction\Read
+ */
+ public function getRejected(int $project_id): array
+ {
+ try {
+ return array_map([$this, 'process'], $this->reservationRepository->fetchRejected($project_id));
+ } catch (Implement\Exception\EmptyResult $exception) {
+ throw new ServiceAction\Read(__CLASS__, $exception);
+ }
+ }
+
+ public function add(array $data): Model\Venta\Reservation
+ {
+ $date = new DateTimeImmutable();
+ try {
+ $date = new DateTimeImmutable($data['date']);
+ } catch (DateMalformedStringException) {}
+ try {
+ $reservation = $this->reservationRepository->fetchByBuyerAndDate($data['buyer_rut'], $date);
+
+ if (array_key_exists('broker_rut', $data) and $data['broker_rut'] !== '') {
+ try {
+ $broker = $this->brokerService->get($data['broker_rut']);
+ $reservation = $this->reservationRepository->edit($reservation, ['broker_rut' => $broker->rut]);
+ } catch (ServiceAction\Read) {}
+ }
+ } catch (Implement\Exception\EmptyResult) {
+ if (!$this->reservationRepository->getConnection()->getPDO()->inTransaction()) {
+ $this->reservationRepository->getConnection()->getPDO()->beginTransaction();
+ }
+ $buyerData = [];
+ foreach ($data as $key => $value) {
+ if (!str_starts_with($key, 'buyer_')) {
+ continue;
+ }
+ $buyerData[substr($key, strlen('buyer_'))] = $value;
+ }
+ $this->personaService->add($buyerData);
+
+ $data['date'] = $date->format('Y-m-d');
+ try {
+ $reservationData = $this->reservationRepository->filterData($data);
+ $reservation = $this->reservationRepository->create($reservationData);
+ $reservation = $this->reservationRepository->save($reservation);
+
+ $stateType = Model\Venta\Reservation\State\Type::INACTIVE;
+ $stateData = [
+ 'reservation_id' => $reservation->id,
+ 'date' => $data['date'],
+ 'type' => $stateType->value,
+ ];
+ $state = $this->stateRepository->create($stateData);
+ $this->stateRepository->save($state);
+
+ $units = array_combine($data['units'], $data['units_value']);
+ $this->addUnits($reservation, $units);
+
+ if (array_key_exists('broker_rut', $data) and !empty($data['broker_rut'])) {
+ $this->addBroker($reservation, $data['broker_rut']);
+ }
+
+ if (array_key_exists('promotions', $data)) {
+ $this->addPromotions($reservation, $data['promotions']);
+ }
+
+ if ($this->reservationRepository->getConnection()->getPDO()->inTransaction()) {
+ $this->reservationRepository->getConnection()->getPDO()->commit();
+ }
+ } catch (PDOException $exception) {
+ $this->logger->warning($exception->getMessage(), ['exception' => $exception->getTraceAsString()]);
+ if ($this->reservationRepository->getConnection()->getPDO()->inTransaction()) {
+ $this->reservationRepository->getConnection()->getPDO()->rollBack();
+ }
+ throw new ServiceAction\Create(__CLASS__, $exception);
+ }
+ }
+
+ return $this->process($reservation);
+ }
public function edit(Define\Model $model, array $new_data): Model\Venta\Reservation
{
try {
@@ -74,8 +202,82 @@ class Reservation extends Ideal\Service\API
throw new ServiceAction\Delete(__CLASS__, $exception);
}
}
+
+ /**
+ * @param Model\Venta\Reservation $reservation
+ * @return void
+ * @throws ServiceAction\Update
+ */
+ public function approve(Model\Venta\Reservation $reservation): void
+ {
+ try {
+ $stateData = [
+ 'reservation_id' => $reservation->id,
+ 'date' => new DateTimeImmutable(),
+ 'type' => Model\Venta\Reservation\State\Type::ACTIVE->value,
+ ];
+ $state = $this->stateRepository->create($stateData);
+ $this->stateRepository->save($state);
+ } catch (PDOException $exception) {
+ throw new ServiceAction\Update(__CLASS__, $exception);
+ }
+ }
+ public function reject(Model\Venta\Reservation $reservation): void
+ {
+ try {
+ $stateData = [
+ 'reservation_id' => $reservation->id,
+ 'date' => new DateTimeImmutable(),
+ 'type' => Model\Venta\Reservation\State\Type::REJECTED->value,
+ ];
+ $state = $this->stateRepository->create($stateData);
+ $this->stateRepository->save($state);
+ } catch (PDOException $exception) {
+ throw new ServiceAction\Update(__CLASS__, $exception);
+ }
+ }
+
protected function process(Define\Model $model): Model\Venta\Reservation
{
+ $model->addFactory('states', new Implement\Repository\Factory()
+ ->setArgs(['reservation_id' => $model->id])
+ ->setCallable(function(int $reservation_id) {
+ return $this->stateRepository->fetchByReservation($reservation_id);
+ })
+ );
+ $model->buyer = $this->personaService->getById($model->buyer->rut);
return $model;
}
+ protected function addUnits(Model\Venta\Reservation $reservation, array $units): void
+ {
+ foreach ($units as $unit_id => $value) {
+ try {
+ $unit = $this->unitService->getById($unit_id);
+ } catch (ServiceAction\Read) {
+ continue;
+ }
+ $reservation->addUnit($unit, $value);
+ }
+ $this->reservationRepository->save($reservation);
+ }
+ protected function addBroker(Model\Venta\Reservation $reservation, int $broker_rut): void
+ {
+ try {
+ $broker = $this->brokerService->get($broker_rut);
+ $reservation->broker = $broker;
+ $this->reservationRepository->save($reservation);
+ } catch (ServiceAction\Read) {}
+ }
+ protected function addPromotions(Model\Venta\Reservation $reservation, array $promotions): void
+ {
+ foreach ($promotions as $promotion_id) {
+ try {
+ $promotion = $this->promotionService->getById($promotion_id);
+ } catch (ServiceAction\Read) {
+ continue;
+ }
+ $reservation->promotions []= $promotion;
+ }
+ $this->reservationRepository->save($reservation);
+ }
}
diff --git a/app/tests/extension/ContainerTrait.php b/app/tests/extension/ContainerTrait.php
new file mode 100644
index 0000000..e8eb309
--- /dev/null
+++ b/app/tests/extension/ContainerTrait.php
@@ -0,0 +1,15 @@
+container = buildContainer();
+ }
+}
diff --git a/app/tests/extension/Seeds/Bancos.php b/app/tests/extension/Seeds/Bancos.php
new file mode 100644
index 0000000..631e595
--- /dev/null
+++ b/app/tests/extension/Seeds/Bancos.php
@@ -0,0 +1,23 @@
+ $this->faker->company,
+ ];
+ }
+
+ $this->table('banco')
+ ->insertValues($data)
+ ->save();
+ }
+}
diff --git a/app/tests/extension/Seeds/BrokerContracts.php b/app/tests/extension/Seeds/BrokerContracts.php
new file mode 100644
index 0000000..9adac33
--- /dev/null
+++ b/app/tests/extension/Seeds/BrokerContracts.php
@@ -0,0 +1,45 @@
+loadValues('brokers', columns: 'rut');
+ $projects = $this->loadValues('proyecto', columns: 'id');
+
+ $data = [];
+ foreach ($projects as $project) {
+ $count = $this->faker->numberBetween(1, count($brokers));
+ for ($i = 0; $i < $count; $i++) {
+ $data []= [
+ 'broker_rut' => $brokers[$i],
+ 'project_id' => $project,
+ 'commission' => $this->faker->randomFloat(4, 0, 1),
+ ];
+ }
+ }
+ $this->table('broker_contracts')->insertValues($data)->save();
+
+ $contracts = $this->loadValues('broker_contracts', columns: 'id');
+ $stateData = [];
+ foreach ($contracts as $contract) {
+ $stateData[]= [
+ 'contract_id' => $contract,
+ 'date' => $this->faker->dateTimeBetween('-1 year'),
+ 'type' => 1
+ ];
+ }
+ $this->table('broker_contract_states')->insertValues($stateData)->save();
+ }
+}
diff --git a/app/tests/extension/Seeds/Brokers.php b/app/tests/extension/Seeds/Brokers.php
new file mode 100644
index 0000000..7ac1a73
--- /dev/null
+++ b/app/tests/extension/Seeds/Brokers.php
@@ -0,0 +1,50 @@
+loadValues('direccion', columns: 'id');
+
+
+
+ $count = 10;
+ $contactData = [];
+ for($i = 0; $i < $count; $i++) {
+ $rut = $this->faker->rut(false, false);
+ $contactData[]= [
+ 'rut' => $rut,
+ 'digit' => $this->faker->digitoVerificador($rut),
+ 'name' => $this->faker->name,
+ 'email' => $this->faker->email,
+ 'phone' => $this->faker->phoneNumber,
+ 'address_id' => $this->faker->randomElement($addresses)
+ ];
+ }
+ $this->table('broker_contacts')->insertValues($contactData)->save();
+
+ $contacts = $this->loadValues('broker_contacts', columns: 'id');
+
+ $data = [];
+ $brokerData = [];
+ for($i = 0; $i < $count; $i ++) {
+ $rut = $this->faker->rut(false, false);
+ $data[] = [
+ 'rut' => $rut,
+ 'digit' => $this->faker->digitoVerificador($rut),
+ 'name' => $this->faker->word
+ ];
+ $brokerData []= [
+ 'broker_rut' => $rut,
+ 'representante_id' => $this->faker->randomElement($contacts),
+ 'legal_name' => $this->faker->company
+ ];
+ }
+
+ $this->table('brokers')->insertValues($data)->save();
+ $this->table('broker_data')->insertValues($brokerData)->save();
+ }
+}
diff --git a/app/tests/extension/Seeds/Direcciones.php b/app/tests/extension/Seeds/Direcciones.php
index a681cf4..09c9eee 100644
--- a/app/tests/extension/Seeds/Direcciones.php
+++ b/app/tests/extension/Seeds/Direcciones.php
@@ -9,14 +9,14 @@ class Direcciones extends AbstractSeed
{
$comunas = $this->loadValues('comuna', columns: 'id');
- $n = 50;
+ $n = 100;
$data = [];
for ($i = 0; $i < $n; $i++) {
$row = [
'calle' => $this->faker->streetName,
'numero' => $this->faker->randomNumber(5),
'comuna' => $this->faker->randomElement($comunas),
- 'extra' => '',
+ 'extra' => $this->faker->optional(0.9, '')->words(2, true),
];
$extraRand = ((int) round(rand() / getrandmax())) === 1;
if ($extraRand) {
diff --git a/app/tests/extension/Seeds/Inmobiliarias.php b/app/tests/extension/Seeds/Inmobiliarias.php
index 04b1238..e8798e6 100644
--- a/app/tests/extension/Seeds/Inmobiliarias.php
+++ b/app/tests/extension/Seeds/Inmobiliarias.php
@@ -5,9 +5,17 @@ use Tests\Extension\AbstractSeed;
class Inmobiliarias extends AbstractSeed
{
+ public function getDependencies(): array
+ {
+ return [
+ Bancos::class
+ ];
+ }
+
public function run(): void
{
$tipos = $this->loadValues('tipo_sociedad', columns: 'id');
+ $bancos = $this->loadValues('banco', columns: 'id');
$suffixes = [
'Inmobiliaria ',
'Administradora ',
@@ -28,8 +36,10 @@ class Inmobiliarias extends AbstractSeed
'dv' => $this->faker->digitoVerificador($rut),
'razon' => $razon,
'abreviacion' => $abreviacion,
- 'sigla' => $sigla,
+ 'cuenta' => $this->faker->randomNumber(8),
+ 'banco' => $this->faker->randomElement($bancos),
'sociedad' => $this->faker->randomElement($tipos),
+ 'sigla' => $sigla,
];
}
$this->table('inmobiliaria')
diff --git a/app/tests/extension/Seeds/Promotions.php b/app/tests/extension/Seeds/Promotions.php
new file mode 100644
index 0000000..00c5293
--- /dev/null
+++ b/app/tests/extension/Seeds/Promotions.php
@@ -0,0 +1,55 @@
+loadValues('proyecto', columns: 'id');
+
+ $data = [];
+ $count = $this->faker->numberBetween(1, 10);
+ for ($i = 0; $i < $count; $i++) {
+ $start = $this->faker->dateTimeBetween('-1 year');
+ $end = $this->faker->dateTimeBetween($start, $start->add(new DateInterval('P1Y')));
+ $data[] = [
+ 'description' => $this->faker->sentence,
+ 'type' => 1,
+ 'amount' => $this->faker->randomFloat(2, 0, 1),
+ 'start_date' => $start,
+ 'end_date' => $end,
+ 'valid_until' => $this->faker->dateTimeBetween($end, $end->add(new DateInterval('P1M'))),
+ 'state' => 1,
+ ];
+ }
+ $this->table('promotions')->insertValues($data)->save();
+
+ $promotions = $this->loadValues('promotions', columns: 'id');
+
+ $data = [];
+ foreach ($projects as $project) {
+ $hasPromo = $this->faker->boolean(10);
+ if (!$hasPromo) {
+ continue;
+ }
+
+ $data []= [
+ 'promotion_id' => $this->faker->randomElement($promotions),
+ 'project_id' => $project,
+ ];
+ }
+ if (count($data) > 0) {
+ $this->table('promotion_projects')->insertValues($data)->save();
+ }
+ }
+}
diff --git a/app/tests/extension/Seeds/ProyectoTipoUnidad.php b/app/tests/extension/Seeds/ProyectoTipoUnidad.php
new file mode 100644
index 0000000..da2c384
--- /dev/null
+++ b/app/tests/extension/Seeds/ProyectoTipoUnidad.php
@@ -0,0 +1,42 @@
+loadValues('proyecto', columns: 'id');
+ $types = $this->loadValues('tipo_unidad', columns: 'id');
+
+ $data = [];
+ foreach ($projects as $project) {
+ foreach ($types as $type) {
+ $count = $this->faker->numberBetween(1, 10);
+ for ($i = 0; $i < $count; $i++) {
+ $name = $this->faker->word;
+ $data []= [
+ 'proyecto' => $project,
+ 'tipo' => $type,
+ 'nombre' => $name,
+ 'abreviacion' => substr($name, 0, 3),
+ 'm2' => $this->faker->randomFloat(2, 10, 100),
+ 'logia' => $this->faker->optional(.3, 0)->randomFloat(2, 1, 5),
+ 'terraza' => $this->faker->optional(.3, 0)->randomFloat(2, 2, 30),
+ 'descripcion' => $this->faker->sentence,
+ ];
+ }
+ }
+ }
+
+ $this->table('proyecto_tipo_unidad')->insertValues($data)->save();
+ }
+}
diff --git a/app/tests/extension/Seeds/Proyectos.php b/app/tests/extension/Seeds/Proyectos.php
index 557e757..3083a4d 100644
--- a/app/tests/extension/Seeds/Proyectos.php
+++ b/app/tests/extension/Seeds/Proyectos.php
@@ -27,9 +27,9 @@ class Proyectos extends AbstractSeed
'direccion' => $this->faker->randomElement($direcciones),
'superficie_sobre_nivel' => $this->faker->randomFloat(2, 1000, 10000),
'superficie_bajo_nivel' => $this->faker->randomFloat(2, 0, 5000),
- 'pisos' => $this->faker->randomNumber(2),
- 'subterraneos' => $this->faker->randomNumber(2),
- 'corredor' => $this->faker->randomFloat(4, 0, 1)
+ 'pisos' => $this->faker->numberBetween(2, 30),
+ 'subterraneos' => $this->faker->numberBetween(0, 5),
+ 'corredor' => $this->faker->optional(.6, 0)->randomFloat(4, 0, 1)
];
}
diff --git a/app/tests/extension/Seeds/Unidades.php b/app/tests/extension/Seeds/Unidades.php
new file mode 100644
index 0000000..b879509
--- /dev/null
+++ b/app/tests/extension/Seeds/Unidades.php
@@ -0,0 +1,47 @@
+loadValues('proyecto_tipo_unidad', columns: ['id', 'proyecto', 'tipo', 'm2', 'logia', 'terraza']);
+
+ $data = [];
+ foreach ($ptus as $s => $ptu) {
+ $count = $this->faker->numberBetween(1, 10);
+ $abr = $this->faker->word;
+ $orientation = $this->faker->randomElement(['N', 'NO', 'NP', 'S', 'SO', 'SP', 'P', 'O']);
+
+ for ($i = 0; $i < $count; $i++) {
+ $data[] = [
+ 'proyecto' => $ptu['proyecto'],
+ 'tipo' => $ptu['tipo'],
+ 'subtipo' => $s,
+ 'piso' => $i + 2,
+ 'descripcion' => ($i + 2) * 100 + $s,
+ 'abreviacion' => $abr,
+ 'm2' => $ptu['m2'],
+ 'logia' => $ptu['logia'],
+ 'cubierta' => 0,
+ 'terraza' => $ptu['terraza'],
+ 'orientacion' => $orientation,
+ 'costo_inmobiliaria' => $this->faker->randomFloat(2, 1000, 3000),
+ 'pt' => $ptu['id'],
+ 'valor' => $this->faker->randomFloat(2, 1000, 3000),
+ ];
+ }
+ }
+
+ $this->table('unidad')->insertValues($data)->save();
+ }
+}
diff --git a/app/tests/integration/API/Ventas/ReservationTest.php b/app/tests/integration/API/Ventas/ReservationTest.php
new file mode 100644
index 0000000..0ec2474
--- /dev/null
+++ b/app/tests/integration/API/Ventas/ReservationTest.php
@@ -0,0 +1,92 @@
+addProvider(new Rut($faker));
+
+ $comunas = $this->container->get(Repository\Comuna::class)->fetchAll();
+ $projects = $this->container->get(Repository\Proyecto::class)->fetchAll();
+ $project = $faker->randomElement($projects);
+ $brokers = $this->container->get(Repository\Proyecto\Broker::class)->fetchAll();
+ $units = $this->container->get(Repository\Venta\Unidad::class)->fetchAll();
+
+ $selectedUnits = [];
+ $unitsValue = [];
+ $unitsCount = $faker->numberBetween(1, 3);
+ for ($i = 0; $i < $unitsCount; $i++) {
+ $selectedUnits[] = $faker->randomElement($units)->id;
+ $unitsValue[] = $faker->randomFloat(2, 1000, 10000);
+ }
+
+ $broker = $faker->randomElement($brokers);
+
+ $activePromotions = $this->container->get(Repository\Venta\Promotion::class)->fetchActiveByProject($project->id);
+
+ $promotionsCount = $faker->numberBetween(0, min(3, count($activePromotions)));
+ $promotions = [];
+ for ($i = 0; $i < $promotionsCount; $i++) {
+ $promotions[] = $faker->randomElement($activePromotions)->id;
+ }
+ $rut = $faker->rut(false, false);
+ $data = [
+ 'project_id' => $faker->randomElement($projects)->id,
+ 'date' => $faker->dateTimeBetween('-2 years', 'now')->format('Y-m-d'),
+ 'buyer_rut' => $rut,
+ 'buyer_digit' => $faker->digitoVerificador($rut),
+ 'buyer_names' => $faker->firstName,
+ 'buyer_last_name' => $faker->lastName,
+ 'buyer_last_name2' => $faker->lastName,
+ 'buyer_email' => $faker->email,
+ 'buyer_phone' => $faker->randomNumber(8),
+ 'buyer_address_street' => $faker->streetName,
+ 'buyer_address_number' => $faker->buildingNumber,
+ 'buyer_address_extra' => $faker->streetAddress,
+ 'buyer_address_comuna_id' => $faker->randomElement($comunas)->id,
+ 'units' => $selectedUnits,
+ 'units_value' => $unitsValue,
+ 'broker_rut' => $broker ? $broker->rut : '',
+ ];
+ if (count($promotions) > 0) {
+ $data['promotions'] = $promotions;
+ }
+
+ $reservation = $this->container->get(Service\Venta\Reservation::class)->add($data);
+ $this->assertInstanceOf(Model\Venta\Reservation::class, $reservation);
+ $this->assertEquals($data['date'], $reservation->date->format('Y-m-d'));
+ $this->assertEquals($data['project_id'], $reservation->project->id);
+ $this->assertEquals($data['buyer_rut'], $reservation->buyer->rut);
+ $this->assertEquals($data['buyer_digit'], $reservation->buyer->digito);
+ $this->assertEquals($data['buyer_names'], $reservation->buyer->nombres);
+ $this->assertEquals($data['buyer_last_name'], $reservation->buyer->apellidoPaterno);
+ $this->assertEquals($data['buyer_last_name2'], $reservation->buyer->apellidoMaterno);
+ $this->assertEquals($data['buyer_email'], $reservation->buyer->datos->email);
+ $this->assertEquals($data['buyer_phone'], $reservation->buyer->datos->telefono);
+ $this->assertEquals($data['buyer_address_street'], $reservation->buyer->datos->direccion->calle);
+ $this->assertEquals($data['buyer_address_number'], $reservation->buyer->datos->direccion->numero);
+ $this->assertEquals($data['buyer_address_extra'], $reservation->buyer->datos->direccion->extra);
+ $this->assertEquals($data['buyer_address_comuna_id'], $reservation->buyer->datos->direccion->comuna->id);
+ if ($broker !== null) {
+ $this->assertEquals($data['broker_rut'], $reservation->broker->rut);
+ }
+ $this->assertEquals(1, $reservation->currentState()->type->value);
+ }
+}
diff --git a/app/tests/integration/QueueTest.php b/app/tests/integration/QueueTest.php
index aa3d601..195765a 100644
--- a/app/tests/integration/QueueTest.php
+++ b/app/tests/integration/QueueTest.php
@@ -11,17 +11,12 @@ use Incoviba\Common\Implement;
use Incoviba\Common\Ideal;
use Incoviba\Service;
use Incoviba\Repository;
+use Tests\Extension\ContainerTrait;
use Tests\Extension\Faker\Provider\Rut;
class QueueTest extends TestCase
{
- protected ContainerInterface $container;
-
- protected function setUp(): void
- {
- require_once implode(DIRECTORY_SEPARATOR, [dirname(__DIR__, 2), 'setup', 'container.php']);
- $this->container = buildContainer();
- }
+ use ContainerTrait;
public function testServiceWorker(): void
{
diff --git a/app/tests/unit/src/Model/Venta/ReservationTest.php b/app/tests/unit/src/Model/Venta/ReservationTest.php
index 593dcb2..298c214 100644
--- a/app/tests/unit/src/Model/Venta/ReservationTest.php
+++ b/app/tests/unit/src/Model/Venta/ReservationTest.php
@@ -13,7 +13,7 @@ class ReservationTest extends AbstractModel
protected function setUp(): void
{
$this->model = new Reservation();
- $this->properties = ['buyer', 'date', 'units', 'promotions', 'broker'];
+ $this->properties = ['project', 'buyer', 'date', 'units', 'promotions', 'broker'];
$this->methods = ['states', 'currentState', 'addUnit', 'removeUnit', 'findUnit', 'hasUnit'];
}
}
diff --git a/app/tests/unit/src/Repository/DireccionTest.php b/app/tests/unit/src/Repository/DireccionTest.php
new file mode 100644
index 0000000..ed57212
--- /dev/null
+++ b/app/tests/unit/src/Repository/DireccionTest.php
@@ -0,0 +1,64 @@
+connection = $this->getMockBuilder(Define\Connection::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->comunaRepository = $this->getMockBuilder(Repository\Comuna::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->comunaRepository->method('fetchById')->willReturnCallback(function ($id) {
+ $comuna = new Model\Comuna();
+ $comuna->id = $id;
+ return $comuna;
+ });
+ }
+
+ public function testCreate(): void
+ {
+ $direccionRepository = new Repository\Direccion($this->connection, $this->comunaRepository);
+
+ $faker = Faker\Factory::create();
+ $data = [
+ 'calle' => $faker->streetName,
+ 'numero' => $faker->randomNumber(),
+ 'extra' => $faker->streetSuffix,
+ 'comuna' => $faker->randomNumber(),
+ ];
+ $direccion = $direccionRepository->create($data);
+
+ $this->assertTrue(!isset($direccion->id));
+ $this->assertEquals($data['calle'], $direccion->calle);
+ $this->assertEquals($data['numero'], $direccion->numero);
+ $this->assertEquals($data['extra'], $direccion->extra);
+ $this->assertEquals($data['comuna'], $direccion->comuna->id);
+ }
+ public function testSave(): void
+ {
+ $direccionRepository = new Repository\Direccion($this->connection, $this->comunaRepository);
+ $faker = Faker\Factory::create();
+
+ $direccion = new Model\Direccion();
+ $direccion->calle = $faker->streetName;
+ $direccion->numero = $faker->randomNumber(3);
+ $direccion->extra = $faker->streetSuffix;
+ $direccion->comuna = $this->getMockBuilder(Model\Comuna::class)->getMock();
+ $direccion->comuna->id = $faker->numberBetween(10000, 18000);
+ $direccion = $direccionRepository->save($direccion);
+
+ $this->assertTrue(isset($direccion->id));
+ }
+}
diff --git a/app/tests/unit/src/Repository/PersonaTest.php b/app/tests/unit/src/Repository/PersonaTest.php
new file mode 100644
index 0000000..6a96ae6
--- /dev/null
+++ b/app/tests/unit/src/Repository/PersonaTest.php
@@ -0,0 +1,62 @@
+connection = $this->getMockBuilder(Define\Connection::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ public function testCreate(): void
+ {
+ $personaRepository = new Repository\Persona($this->connection);
+ $faker = Faker\Factory::create();
+
+ $data = [
+ 'rut' => $faker->randomNumber(8),
+ 'digito' => $faker->boolean(100 - round(1 / 11 * 100)) ? $faker->randomNumber(1) : 'K',
+ 'nombres' => $faker->name(),
+ 'apellido_paterno' => $faker->lastName(),
+ 'apellido_materno' => $faker->lastName()
+ ];
+ $persona = $personaRepository->create($data);
+
+ $this->assertEquals($data['rut'], $persona->rut);
+ $this->assertEquals($data['digito'], $persona->digito);
+ $this->assertEquals($data['nombres'], $persona->nombres);
+ $this->assertEquals($data['apellido_paterno'], $persona->apellidoPaterno);
+ $this->assertEquals($data['apellido_materno'], $persona->apellidoMaterno);
+ }
+ public function testSave(): void
+ {
+ $personaRepository = new Repository\Persona($this->connection);
+ $faker = Faker\Factory::create();
+
+ $data = [
+ 'rut' => $faker->randomNumber(8),
+ 'digito' => $faker->boolean(100 - round(1 / 11 * 100)) ? $faker->randomNumber(1) : 'K',
+ 'nombres' => $faker->name(),
+ 'apellido_paterno' => $faker->lastName(),
+ 'apellido_materno' => $faker->lastName()
+ ];
+ $persona = new Model\Persona();
+ $persona->rut = $data['rut'];
+ $persona->digito = $data['digito'];
+ $persona->nombres = $data['nombres'];
+ $persona->apellidoPaterno = $data['apellido_paterno'];
+ $persona->apellidoMaterno = $data['apellido_materno'];
+ $persona = $personaRepository->save($persona);
+ $this->assertEquals($data['rut'], $persona->rut);
+ }
+}
diff --git a/app/tests/unit/src/Repository/Venta/ReservationTest.php b/app/tests/unit/src/Repository/Venta/ReservationTest.php
new file mode 100644
index 0000000..618dc86
--- /dev/null
+++ b/app/tests/unit/src/Repository/Venta/ReservationTest.php
@@ -0,0 +1,102 @@
+connection = $this->getMockBuilder(Define\Connection::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->proyectoRepository = $this->getMockBuilder(Repository\Proyecto::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->proyectoRepository->method('fetchById')->willReturnCallback(function ($id) {
+ $proyecto = new Model\Proyecto();
+ $proyecto->id = $id;
+ return $proyecto;
+ });
+ $this->personaRepository = $this->getMockBuilder(Repository\Persona::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->personaRepository->method('fetchById')->willReturnCallback(function ($rut) {
+ $persona = new Model\Persona();
+ $persona->rut = $rut;
+ return $persona;
+ });
+ $this->brokerRepository = $this->getMockBuilder(Repository\Proyecto\Broker::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->brokerRepository->method('fetchById')->willReturnCallback(function ($rut) {
+ $broker = new Model\Proyecto\Broker();
+ $broker->rut = $rut;
+ return $broker;
+ });
+ $this->unitRepository = $this->getMockBuilder(Repository\Venta\Unidad::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->unitRepository->method('fetchById')->willReturnCallback(function ($id) {
+ $unidad = new Model\Venta\Unidad();
+ $unidad->id = $id;
+ return $unidad;
+ });
+ $this->promotionRepository = $this->getMockBuilder(Repository\Venta\Promotion::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->promotionRepository->method('fetchById')->willReturnCallback(function ($id) {
+ $promotion = new Model\Venta\Promotion();
+ $promotion->id = $id;
+ return $promotion;
+ });
+ }
+
+ public function testCreate(): void
+ {
+ $reservationRepository = new Repository\Venta\Reservation($this->connection, $this->proyectoRepository,
+ $this->personaRepository, $this->brokerRepository, $this->unitRepository, $this->promotionRepository);
+ $faker = Faker\Factory::create();
+ $data = [
+ 'project_id' => $faker->numberBetween(1, 10),
+ 'buyer_rut' => $faker->randomNumber(8),
+ 'date' => $faker->dateTimeBetween('-2 years', 'now')->format('Y-m-d'),
+ ];
+ $reservation = $reservationRepository->create($data);
+
+ $this->assertTrue(!isset($reservation->id));
+ $this->assertEquals($data['project_id'], $reservation->project->id);
+ $this->assertEquals($data['buyer_rut'], $reservation->buyer->rut);
+ $this->assertEquals($data['date'], $reservation->date->format('Y-m-d'));
+ }
+ public function testSave(): void
+ {
+ $reservationRepository = new Repository\Venta\Reservation($this->connection, $this->proyectoRepository,
+ $this->personaRepository, $this->brokerRepository, $this->unitRepository, $this->promotionRepository);
+ $faker = Faker\Factory::create();
+ $data = [
+ 'project_id' => $faker->numberBetween(1, 10),
+ 'buyer_rut' => $faker->randomNumber(8),
+ 'date' => $faker->dateTimeBetween('-2 years', 'now')->format('Y-m-d'),
+ ];
+ $reservation = new Model\Venta\Reservation();
+ $reservation->project = $this->proyectoRepository->fetchById($data['project_id']);
+ $reservation->buyer = $this->personaRepository->fetchById($data['buyer_rut']);
+ $reservation->date = new DateTimeImmutable($data['date']);
+ $reservation = $reservationRepository->save($reservation);
+
+ $this->assertTrue(isset($reservation->id));
+ }
+}
diff --git a/app/tests/unit/src/Service/DireccionTest.php b/app/tests/unit/src/Service/DireccionTest.php
new file mode 100644
index 0000000..aa6d425
--- /dev/null
+++ b/app/tests/unit/src/Service/DireccionTest.php
@@ -0,0 +1,64 @@
+logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
+ $this->direccionRepository = $this->getMockBuilder(Repository\Direccion::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->direccionRepository->method('fetchByCalleAndNumeroAndExtraAndComuna')
+ ->willThrowException(new Implement\Exception\EmptyResult(''));
+ $this->direccionRepository->method('filterData')->willReturnArgument(0);
+ $this->direccionRepository->method('create')->willReturnCallback(function($data) {
+ $direccion = new Model\Direccion();
+ $direccion->calle = $data['calle'];
+ $direccion->numero = $data['numero'];
+ $direccion->extra = $data['extra'];
+ $direccion->comuna = $this->getMockBuilder(Model\Comuna::class)
+ ->disableOriginalConstructor()->getMock();
+ $direccion->comuna->id = $data['comuna'];
+ return $direccion;
+ });
+ $this->direccionRepository->method('save')->willReturnCallback(function($direccion) {
+ $direccion->id = 1;
+ return $direccion;
+ });
+ }
+
+ public function testAdd(): void
+ {
+ $direccionService = new Service\Direccion($this->logger, $this->direccionRepository);
+ $faker = Faker\Factory::create('es_ES');
+
+ $data = [
+ 'street' => $faker->streetName,
+ 'number' => $faker->randomNumber(3),
+ 'extra' => $faker->word,
+ 'comuna_id' => $faker->numberBetween(10000, 18000),
+ ];
+ $direccion = $direccionService->add($data);
+
+ $this->assertEquals($data['street'], $direccion->calle);
+ $this->assertEquals($data['number'], $direccion->numero);
+ $this->assertEquals($data['extra'], $direccion->extra);
+ $this->assertEquals($data['comuna_id'], $direccion->comuna->id);
+ }
+}
diff --git a/app/tests/unit/src/Service/PersonaTest.php b/app/tests/unit/src/Service/PersonaTest.php
new file mode 100644
index 0000000..ff5c83b
--- /dev/null
+++ b/app/tests/unit/src/Service/PersonaTest.php
@@ -0,0 +1,65 @@
+logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
+ $this->personaRepository = $this->getMockBuilder(Repository\Persona::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->personaRepository->method('fetchById')->willThrowException(new Implement\Exception\EmptyResult(''));
+ $this->personaRepository->method('filterData')->willReturnArgument(0);
+ $this->personaRepository->method('create')->willReturnCallback(function($data) {
+ $persona = new Model\Persona();
+ $persona->rut = $data['rut'];
+ $persona->digito = $data['digito'];
+ $persona->nombres = $data['nombres'];
+ $persona->apellidoPaterno = $data['apellido_paterno'];
+ $persona->apellidoMaterno = $data['apellido_materno'];
+ return $persona;
+ });
+ $this->personaRepository->method('save')->willReturnArgument(0);
+ $this->datosPersonaRepository = $this->getMockBuilder(Repository\Persona\Datos::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->propietarioRepository = $this->getMockBuilder(Repository\Venta\Propietario::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->propietarioRepository->method('fetchById')->willThrowException(new Implement\Exception\EmptyResult(''));
+ $this->direccionService = $this->getMockBuilder(Service\Direccion::class)
+ ->disableOriginalConstructor()->getMock();
+ }
+
+ public function testAdd(): void
+ {
+ $personaService = new Service\Persona($this->logger, $this->personaRepository, $this->datosPersonaRepository,
+ $this->propietarioRepository, $this->direccionService);
+ $faker = Faker\Factory::create('es_ES');
+ $digit = $faker->boolean(100-round(1/11*100)) ? $faker->randomNumber(1) : 'K';
+ $data = [
+ 'rut' => $faker->randomNumber(8),
+ 'digito' => $digit,
+ 'nombres' => $faker->name(),
+ 'apellido_paterno' => $faker->lastName(),
+ 'apellido_materno' => $faker->lastName(),
+ ];
+ $persona = $personaService->add($data);
+ $this->assertEquals($data['rut'], $persona->rut);
+ }
+}
diff --git a/app/tests/unit/src/Service/ValorTest.php b/app/tests/unit/src/Service/ValorTest.php
index 667c92f..5cea05b 100644
--- a/app/tests/unit/src/Service/ValorTest.php
+++ b/app/tests/unit/src/Service/ValorTest.php
@@ -3,18 +3,22 @@ namespace Tests\Unit\Service;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\DataProvider;
+use Faker\Factory;
use Incoviba\Service\Valor;
use Incoviba\Service;
class ValorTest extends TestCase
{
protected Service\UF $ufService;
+ protected static float $staticUF = 35498.76;
+
protected function setUp(): void
{
$this->ufService = $this->getMockBuilder(Service\UF::class)
->disableOriginalConstructor()
->getMock();
- $this->ufService->method('get')->willReturn(35000.0);
+ $faker = Factory::create();
+ $this->ufService->method('get')->willReturn(self::$staticUF);
}
public static function cleanDataProvider(): array
@@ -55,14 +59,14 @@ class ValorTest extends TestCase
$result = $valorService->toUF($input, $date);
$this->assertIsFloat($result);
- $this->assertEquals($input / 35000, $result);
+ $this->assertEquals($input / self::$staticUF, $result);
}
public static function pesosDataProvider(): array
{
return [
- [1000.01, 1000.01*35000, false],
- [1000, 1000*35000, true],
+ [1000.01, round(1000.01*self::$staticUF), false],
+ [1000, round(1000*self::$staticUF), true],
['1000', 1000, false],
];
}
diff --git a/app/tests/unit/src/Service/Venta/BonoPieTest.php b/app/tests/unit/src/Service/Venta/BonoPieTest.php
new file mode 100644
index 0000000..6d739a6
--- /dev/null
+++ b/app/tests/unit/src/Service/Venta/BonoPieTest.php
@@ -0,0 +1,65 @@
+dateTimeBetween('-1 week');
+ $data = [
+ 'fecha' => $fecha->format('Y-m-d'),
+ 'valor' => $faker->randomFloat(2, 100, 1000),
+ ];
+
+ $uf = $faker->randomFloat(2, 20000, 40000);
+ $pago = new Model\Venta\Pago();
+ $pago->id = $faker->randomNumber();
+ $pago->fecha = $fecha;
+ $pago->valor = $data['valor'] * $uf;
+ $pago->uf = $uf;
+ $bonoPie = new Model\Venta\BonoPie();
+ $bonoPie->valor = $data['valor'];
+ $bonoPie->pago = $pago;
+
+ $logger = $this->getMockBuilder(LoggerInterface::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $bonoPieRepository = $this->getMockBuilder(Repository\Venta\BonoPie::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $bonoPieRepository->method('fetchByPago')->willThrowException(new Implement\Exception\EmptyResult('fetchByPago'));
+ $bonoPieRepository->method('create')->willReturn($bonoPie);
+ $bonoPieRepository->method('save')->willReturnCallback(function($bonoPie) use ($faker) {
+ $bonoPie->id = $faker->randomNumber();
+ return $bonoPie;
+ });
+ $bonoPieRepository->method('filterData')->willReturnCallback(function($data) {
+ return array_intersect_key($data, array_flip(['valor', 'pago']));
+ });
+ $valorService = $this->getMockBuilder(Service\Valor::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $valorService->method('toUF')->willReturn($data['valor']);
+ $ufService = $this->getMockBuilder(Service\UF::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $ufService->method('get')->with($fecha)->willReturn($uf);
+ $pagoService = $this->getMockBuilder(Service\Venta\Pago::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $pagoService->method('add')->willReturn($pago);
+
+ $bonoPieService = new Service\Venta\BonoPie($logger, $bonoPieRepository, $valorService, $ufService, $pagoService);
+
+ $this->assertEquals($bonoPie, $bonoPieService->add($data));
+ }
+}
diff --git a/app/tests/unit/src/Service/Venta/PagoTest.php b/app/tests/unit/src/Service/Venta/PagoTest.php
index 830a172..e983f7e 100644
--- a/app/tests/unit/src/Service/Venta/PagoTest.php
+++ b/app/tests/unit/src/Service/Venta/PagoTest.php
@@ -1,5 +1,5 @@
assertTrue($status);
$this->assertEquals($pago->uf, $this->uf);
}
-}
\ No newline at end of file
+}
diff --git a/app/tests/unit/src/Service/Venta/ReservationTest.php b/app/tests/unit/src/Service/Venta/ReservationTest.php
new file mode 100644
index 0000000..ca31e38
--- /dev/null
+++ b/app/tests/unit/src/Service/Venta/ReservationTest.php
@@ -0,0 +1,139 @@
+logger = $this->getMockBuilder(LoggerInterface::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->reservationRepository = $this->getMockBuilder(Repository\Venta\Reservation::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->reservationRepository->method('fetchByBuyerAndDate')->willThrowException(new Implement\Exception\EmptyResult(''));
+ $this->reservationRepository->method('filterData')->willReturnArgument(0);
+ $this->reservationRepository->method('create')->willReturnCallback(function($data) {
+ $reservation = new Model\Venta\Reservation();
+ $reservation->buyer = $this->getMockBuilder(Model\Persona::class)->disableOriginalConstructor()->getMock();
+ $reservation->buyer->rut = $data['buyer_rut'];
+ $reservation->project = $this->getMockBuilder(Model\Proyecto::class)->disableOriginalConstructor()->getMock();
+ $reservation->project->id = $data['project_id'];
+ $reservation->date = new DateTimeImmutable($data['date']);
+ if (array_key_exists('broker_rut', $data) and !empty($data['broker_rut'])) {
+ $reservation->broker = $this->getMockBuilder(Model\Proyecto\Broker::class)->disableOriginalConstructor()->getMock();
+ $reservation->broker->rut = $data['broker_rut'];
+ }
+ return $reservation;
+ });
+ $this->reservationRepository->method('save')->willReturnCallback(function($reservation) {
+ $reservation->id = 1;
+ return $reservation;
+ });
+ $this->stateRepository = $this->getMockBuilder(Repository\Venta\Reservation\State::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->stateRepository->method('fetchByReservation')->willReturnCallback(function($reservation_id) {
+ $state = new Model\Venta\Reservation\State();
+ $state->reservation = new Model\Venta\Reservation();
+ $state->reservation->id = $reservation_id;
+ return $state;
+ });
+ $this->personaService = $this->getMockBuilder(Service\Persona::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->personaService->method('add')->willReturnCallback(function($data) {
+ $persona = new Model\Persona();
+ $persona->rut = $data['rut'];
+ return $persona;
+ });
+ $this->personaService->method('getById')->willReturnCallback(function($id) {
+ $persona = new Model\Persona();
+ $persona->rut = $id;
+ return $persona;
+ });
+ $this->brokerService = $this->getMockBuilder(Service\Proyecto\Broker::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->brokerService->method('get')->willReturnCallback(function($id) {
+ $broker = new Model\Proyecto\Broker();
+ $broker->rut = $id;
+ return $broker;
+ });
+ $this->promotionService = $this->getMockBuilder(Service\Venta\Promotion::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->promotionService->method('getById')->willReturnCallback(function($id) {
+ $promotion = new Model\Venta\Promotion();
+ $promotion->id = $id;
+ return $promotion;
+ });
+ $this->unitService = $this->getMockBuilder(Service\Venta\Unidad::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->unitService->method('getById')->willReturnCallback(function($id) {
+ $unit = new Model\Venta\Unidad();
+ $unit->id = $id;
+ return $unit;
+ });
+ }
+
+ public function testAdd(): void
+ {
+ $faker = Faker\Factory::create();
+ $reservationService = new Service\Venta\Reservation($this->logger, $this->reservationRepository,
+ $this->stateRepository, $this->personaService, $this->brokerService, $this->promotionService,
+ $this->unitService);
+
+ $units = [];
+ $unitsValue = [];
+ $unitsCount = $faker->numberBetween(1, 10);
+ for ($i = 0; $i < $unitsCount; $i++) {
+ $units[] = $faker->unique()->numberBetween(1, 100);
+ $unitsValue[] = $faker->randomFloat(2, 1000, 10000);
+ }
+ $digit = $faker->boolean(100-round(1/11*100)) ? $faker->randomNumber(1) : 'K';
+ $broker = $faker->boolean(10) ? $faker->randomNumber(8, true) : '';
+ $promotions = [];
+ $promotionsCount = $faker->numberBetween(0, 3);
+ for ($i = 0; $i < $promotionsCount; $i++) {
+ $promotions[] = $faker->numberBetween(1, 100);
+ }
+
+ $data = [
+ 'project_id' => $faker->numberBetween(1, 100),
+ 'date' => $faker->dateTimeBetween('-1 year', 'now')->format('Y-m-d'),
+ 'buyer_rut' => $faker->randomNumber(8, true),
+ 'buyer_digit' => $digit,
+ 'buyer_names' => $faker->firstName(),
+ 'buyer_last_name' => $faker->lastName(),
+ 'buyer_last_name2' => $faker->lastName(),
+ 'buyer_address_street' => $faker->streetName(),
+ 'buyer_address_number' => $faker->randomNumber(3),
+ 'buyer_address_comuna' => $faker->numberBetween(10000, 18000),
+ 'buyer_marital_status' => $faker->word(),
+ 'buyer_email' => $faker->email(),
+ 'buyer_phone' => $faker->randomNumber(9),
+ 'buyer_profession' => $faker->word(),
+ 'buyer_birthdate' => $faker->dateTimeBetween('-80 year', '-18 year')->format('Y-m-d'),
+ 'units' => $units,
+ 'units_value' => $unitsValue,
+ 'broker_rut' => $broker,
+ 'promotions' => $promotions
+ ];
+ $reservation = $reservationService->add($data);
+ $this->assertEquals($data['project_id'], $reservation->project->id);
+ $this->assertEquals($data['buyer_rut'], $reservation->buyer->rut);
+ $this->assertCount($unitsCount, $reservation->units);
+ }
+}