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/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..bce17b4 100644 --- a/app/src/Model/Venta/Reservation.php +++ b/app/src/Model/Venta/Reservation.php @@ -7,11 +7,44 @@ use Incoviba\Model; 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); + } + return $price; + } + protected array $states = []; public function states(): array @@ -38,13 +71,12 @@ class Reservation extends Common\Ideal\Model $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,7 +86,6 @@ 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) { @@ -64,20 +95,43 @@ class Reservation extends Common\Ideal\Model } return null; } - 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..efe1a6d 100644 --- a/app/src/Model/Venta/Reservation/State/Type.php +++ b/app/src/Model/Venta/Reservation/State/Type.php @@ -7,13 +7,11 @@ enum Type: int case INACTIVE = 0; case REJECTED = -1; - 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 +} diff --git a/app/src/Repository/Venta/Reservation.php b/app/src/Repository/Venta/Reservation.php index 8ff13c7..de990b5 100644 --- a/app/src/Repository/Venta/Reservation.php +++ b/app/src/Repository/Venta/Reservation.php @@ -3,14 +3,18 @@ namespace Incoviba\Repository\Venta; use DateTimeInterface; use DateInterval; +use Incoviba\Common\Define; 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 +29,33 @@ 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) use ($data) { + return $this->proyectoRepository->fetchById($data['project_id']); + })) ->register('buyer_rut', (new Common\Implement\Repository\Mapper()) ->setProperty('buyer') ->setFunction(function($data) use ($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([ + 'project_id', 'buyer_rut', - 'date', - 'broker_rut' + 'date' ], [ + $model->project->id, $model->buyer->rut, - $model->date->format('Y-m-d'), - $model->broker?->rut + $model->date->format('Y-m-d') ]); $this->saveUnits($model); $this->savePromotions($model); + $this->saveBroker($model); return $model; } @@ -67,15 +67,20 @@ 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); + $this->fetchBroker($model, $data_row); + $this->fetchPromotions($model, $data_row); return $model; } @@ -101,22 +106,71 @@ 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('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); + $new_id = $reservation->broker->id; + $reservation->broker = $this->brokerRepository->fetchById($result['id']); + $this->editBroker($reservation, ['broker_id' => $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->id + ]); } } protected function savePromotions(Model\Venta\Reservation $reservation): void @@ -126,60 +180,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_id', $new_data) or $new_data['broker_id'] === $reservation->broker->id) { + return; + } + try { + $query = $this->connection->getQueryBuilder() + ->update('reservation_details') + ->set('reference_id = :broker_id') + ->where('reservation_id = :id AND type = :type'); + $this->connection->execute($query, [ + 'id' => $reservation->id, + 'type' => Model\Venta\Reservation\Detail\Type::Broker->value, + 'broker_id' => $new_data['broker_id'] + ]); + $reservation->broker = $this->brokerRepository->fetchById($new_data['broker_id']); + } 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 +344,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 = ?'); + $statement = $this->connection->execute($query, [ + 'id' => $reservation->id, + Model\Venta\Reservation\Detail\Type::Unit->value + ]); while ($result = $statement->fetch(PDO::FETCH_ASSOC)) { try { @@ -213,13 +372,69 @@ 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; + } + 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); + $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 +442,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/Service/Venta/Reservation.php b/app/src/Service/Venta/Reservation.php index 9ceca60..f5a172e 100644 --- a/app/src/Service/Venta/Reservation.php +++ b/app/src/Service/Venta/Reservation.php @@ -14,7 +14,9 @@ use Incoviba\Repository; class Reservation extends Ideal\Service\API { - public function __construct(LoggerInterface $logger, protected Repository\Venta\Reservation $reservationRepository) + public function __construct(LoggerInterface $logger, + protected Repository\Venta\Reservation $reservationRepository, + protected Repository\Venta\Reservation\State $stateRepository) { parent::__construct($logger); } @@ -22,7 +24,7 @@ class Reservation extends Ideal\Service\API public function getAll(null|string|array $order = null): array { try { - return $this->reservationRepository->fetchAll($order); + return array_map([$this, 'process'], $this->reservationRepository->fetchAll($order)); } catch (Implement\Exception\EmptyResult) { return []; } @@ -76,6 +78,12 @@ class Reservation extends Ideal\Service\API } 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); + }) + ); return $model; } }