Files
oficial/app/src/Repository/Venta/Reservation.php

566 lines
24 KiB
PHP
Raw Normal View History

2025-02-18 16:02:10 -03:00
<?php
namespace Incoviba\Repository\Venta;
2025-03-03 14:55:57 -03:00
use DateTimeInterface;
use DateInterval;
2025-07-22 18:20:48 -04:00
use Incoviba\Common\Define;
2025-08-08 17:04:50 -04:00
use Incoviba\Exception\Model\InvalidState;
2025-02-18 16:02:10 -03:00
use PDO;
use Incoviba\Common;
use Incoviba\Model;
use Incoviba\Repository;
2025-07-22 18:20:48 -04:00
use PDOException;
2025-02-18 16:02:10 -03:00
class Reservation extends Common\Ideal\Repository
{
2025-07-22 18:20:48 -04:00
public function __construct(Common\Define\Connection $connection,
protected Repository\Proyecto $proyectoRepository,
protected Repository\Persona $personaRepository,
2025-02-18 16:02:10 -03:00
protected Repository\Proyecto\Broker $brokerRepository,
protected Unidad $unitRepository, protected Promotion $promotionRepository)
{
parent::__construct($connection);
}
2025-02-24 12:39:42 -03:00
public function getTable(): string
{
return 'reservations';
}
2025-02-18 16:02:10 -03:00
public function create(?array $data = null): Model\Venta\Reservation
{
$map = (new Common\Implement\Repository\MapperParser())
2025-07-22 18:20:48 -04:00
->register('project_id', (new Common\Implement\Repository\Mapper())
->setProperty('project')
2025-08-08 17:04:50 -04:00
->setFunction(function($data) {
2025-07-22 18:20:48 -04:00
return $this->proyectoRepository->fetchById($data['project_id']);
}))
2025-02-18 16:02:10 -03:00
->register('buyer_rut', (new Common\Implement\Repository\Mapper())
->setProperty('buyer')
2025-08-08 17:04:50 -04:00
->setFunction(function($data) {
2025-02-18 16:02:10 -03:00
return $this->personaRepository->fetchById($data['buyer_rut']);
}))
2025-07-22 18:20:48 -04:00
->register('date', new Common\Implement\Repository\Mapper\DateTime('date'));
2025-02-18 16:02:10 -03:00
return $this->parseData(new Model\Venta\Reservation(), $data, $map);
}
public function save(Common\Define\Model $model): Model\Venta\Reservation
{
$model->id = $this->saveNew([
2025-07-22 18:20:48 -04:00
'project_id',
2025-02-18 16:02:10 -03:00
'buyer_rut',
2025-07-22 18:20:48 -04:00
'date'
2025-02-18 16:02:10 -03:00
], [
2025-07-22 18:20:48 -04:00
$model->project->id,
2025-02-18 16:02:10 -03:00
$model->buyer->rut,
2025-07-22 18:20:48 -04:00
$model->date->format('Y-m-d')
2025-02-18 16:02:10 -03:00
]);
$this->saveUnits($model);
$this->savePromotions($model);
2025-07-22 18:20:48 -04:00
$this->saveBroker($model);
2025-02-18 16:02:10 -03:00
return $model;
}
2025-03-03 14:55:57 -03:00
/**
* @param Common\Define\Model $model
* @param array $new_data
* @return Model\Venta\Reservation
* @throws Common\Implement\Exception\EmptyResult
*/
2025-02-18 16:02:10 -03:00
public function edit(Common\Define\Model $model, array $new_data): Model\Venta\Reservation
{
2025-07-22 18:20:48 -04:00
$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;
2025-02-18 16:02:10 -03:00
}
public function load(array $data_row): Model\Venta\Reservation
{
$model = parent::load($data_row);
2025-07-22 18:20:48 -04:00
$this->fetchUnits($model, $data_row);
$this->fetchBroker($model, $data_row);
$this->fetchPromotions($model, $data_row);
2025-02-18 16:02:10 -03:00
return $model;
}
2025-03-03 14:55:57 -03:00
/**
* @param int $buyer_rut
* @param DateTimeInterface $date
* @return Model\Venta\Reservation
* @throws Common\Implement\Exception\EmptyResult
*/
public function fetchByBuyerAndDate(int $buyer_rut, DateTimeInterface $date): Model\Venta\Reservation
{
$query = $this->connection->getQueryBuilder()
->select()
->from('reservations')
->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')]);
}
2025-08-08 17:04:50 -04:00
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()
->from('reservations')
->joined("INNER JOIN ({$sub2}) er ON er.reservation_id = reservations.id")
->where('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);
} catch (InvalidState $exception) {
throw new Common\Implement\Exception\EmptyResult('Select rejected reservations', $exception);
}
}
2025-03-03 14:55:57 -03:00
2025-02-18 16:02:10 -03:00
protected function saveUnits(Model\Venta\Reservation $reservation): void
{
if (empty($reservation->units)) {
return;
}
$queryCheck = $this->connection->getQueryBuilder()
->select('COUNT(id) AS cnt')
2025-07-22 18:20:48 -04:00
->from('reservation_details')
->where('reservation_id = :id AND type = :type AND reference_id = :unit_id');
2025-02-18 16:02:10 -03:00
$statementCheck = $this->connection->prepare($queryCheck);
$queryInsert = $this->connection->getQueryBuilder()
->insert()
2025-07-22 18:20:48 -04:00
->into('reservation_details')
2025-02-18 16:02:10 -03:00
->columns(['reservation_id', 'type', 'reference_id', 'value'])
->values([':reservation_id', ':type', ':reference_id', ':value']);
$statementInsert = $this->connection->prepare($queryInsert);
foreach ($reservation->units as $unit) {
2025-07-22 18:20:48 -04:00
$statementCheck->execute([
'id' => $reservation->id,
'type' => Model\Venta\Reservation\Detail\Type::Unit->value,
'unit_id' => $unit->unit->id
]);
2025-02-18 16:02:10 -03:00
$result = $statementCheck->fetch(PDO::FETCH_ASSOC);
if ($result['cnt'] > 0) {
continue;
}
2025-07-22 18:20:48 -04:00
$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
]);
2025-02-18 16:02:10 -03:00
}
}
protected function savePromotions(Model\Venta\Reservation $reservation): void
{
if (empty($reservation->promotions)) {
return;
}
$queryCheck = $this->connection->getQueryBuilder()
->select('COUNT(id) AS cnt')
2025-07-22 18:20:48 -04:00
->from('reservation_details')
->where('reservation_id = :id AND type = :type AND reference_id = :promotion_id');
2025-02-18 16:02:10 -03:00
$statementCheck = $this->connection->prepare($queryCheck);
$queryInsert = $this->connection->getQueryBuilder()
->insert()
2025-07-22 18:20:48 -04:00
->into('reservation_details')
2025-02-18 16:02:10 -03:00
->columns(['reservation_id', 'type', 'reference_id'])
->values([':reservation_id', ':type', ':reference_id']);
$statementInsert = $this->connection->prepare($queryInsert);
foreach ($reservation->promotions as $promotion) {
2025-07-22 18:20:48 -04:00
$statementCheck->execute([
'id' => $reservation->id,
'type' => Model\Venta\Reservation\Detail\Type::Promotion->value,
'promotion_id' => $promotion->id
]);
2025-02-18 16:02:10 -03:00
$result = $statementCheck->fetch(PDO::FETCH_ASSOC);
if ($result['cnt'] > 0) {
continue;
}
2025-07-22 18:20:48 -04:00
$statementInsert->execute([
'reservation_id' => $reservation->id,
'type' => Model\Venta\Reservation\Detail\Type::Promotion->value,
'reference_id' => $promotion->id
]);
2025-02-18 16:02:10 -03:00
}
2025-07-22 18:20:48 -04:00
$this->cleanUpPromotions($reservation);
}
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));
2025-02-18 16:02:10 -03:00
}
2025-07-22 18:20:48 -04:00
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
2025-02-18 16:02:10 -03:00
{
$querySelect = $this->connection->getQueryBuilder()
->select()
2025-07-22 18:20:48 -04:00
->from('reservation_details')
->where('reservation_id = :id AND type = :type AND reference_id = :unit_id');
2025-02-18 16:02:10 -03:00
$statementSelect = $this->connection->prepare($querySelect);
$queryUpdate = $this->connection->getQueryBuilder()
2025-07-22 18:20:48 -04:00
->update('reservation_details')
2025-02-18 16:02:10 -03:00
->set('value = :value')
2025-07-22 18:20:48 -04:00
->where('reservation_id = :id AND type = :type AND reference_id = :unit_id');
2025-02-18 16:02:10 -03:00
$statementUpdate = $this->connection->prepare($queryUpdate);
2025-07-22 18:20:48 -04:00
$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']);
2025-02-18 16:02:10 -03:00
if ($idx === null) {
2025-07-22 18:20:48 -04:00
$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']
]);
2025-02-18 16:02:10 -03:00
continue;
}
2025-07-22 18:20:48 -04:00
$statementSelect->execute([
'id' => $reservation->id,
'type' => Model\Venta\Reservation\Detail\Type::Unit->value,
'unit_id' => $unit['unit_id']
]);
2025-02-18 16:02:10 -03:00
$result = $statementSelect->fetch(PDO::FETCH_ASSOC);
if (!$result) {
2025-07-22 18:20:48 -04:00
$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']
]);
2025-02-18 16:02:10 -03:00
continue;
}
2025-07-22 18:20:48 -04:00
$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'];
2025-02-18 16:02:10 -03:00
}
}
2025-07-22 18:20:48 -04:00
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
2025-02-18 16:02:10 -03:00
{
$querySelect = $this->connection->getQueryBuilder()
->select()
2025-07-22 18:20:48 -04:00
->from('reservation_details')
2025-02-18 16:02:10 -03:00
->where('reservation_id = :id AND type = "Promotion" AND reference_id = :promotion_id');
$statementSelect = $this->connection->prepare($querySelect);
$queryUpdate = $this->connection->getQueryBuilder()
2025-07-22 18:20:48 -04:00
->update('reservation_details')
2025-02-18 16:02:10 -03:00
->set('value = :value')
->where('reservation_id = :id AND type = "Promotion" AND reference_id = :promotion_id');
$statementUpdate = $this->connection->prepare($queryUpdate);
foreach ($new_data as $promotion_id => $value) {
$idx = array_search($promotion_id, array_column($reservation->promotions, 'id'));
if ($idx === false) {
$reservation->promotions []= $this->promotionRepository->fetchById($promotion_id);
continue;
}
$statementSelect->execute(['id' => $reservation->id, 'promotion_id' => $promotion_id]);
$result = $statementSelect->fetch(PDO::FETCH_ASSOC);
if (!$result) {
continue;
}
$statementUpdate->execute(['id' => $reservation->id, 'promotion_id' => $promotion_id, 'value' => $value]);
$reservation->promotions[$idx] = $this->promotionRepository->fetchById($promotion_id);
}
}
2025-07-22 18:20:48 -04:00
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
2025-02-18 16:02:10 -03:00
{
$query = $this->connection->getQueryBuilder()
->select()
2025-07-22 18:20:48 -04:00
->from('reservation_details')
->where('reservation_id = :id AND type = ?');
$statement = $this->connection->execute($query, [
'id' => $reservation->id,
Model\Venta\Reservation\Detail\Type::Unit->value
]);
2025-02-18 16:02:10 -03:00
while ($result = $statement->fetch(PDO::FETCH_ASSOC)) {
try {
$reservation->addUnit($this->unitRepository->fetchById($result['reference_id']), $result['value']);
} catch (Common\Implement\Exception\EmptyResult) {}
}
return $reservation;
}
2025-07-22 18:20:48 -04:00
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
2025-02-18 16:02:10 -03:00
{
$query = $this->connection->getQueryBuilder()
->select()
2025-07-22 18:20:48 -04:00
->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]);
2025-02-18 16:02:10 -03:00
while ($result = $statement->fetch(PDO::FETCH_ASSOC)) {
try {
$reservation->promotions []= $this->promotionRepository->fetchById($result['reference_id']);
} catch (Common\Implement\Exception\EmptyResult) {}
}
return $reservation;
}
2025-07-22 18:20:48 -04:00
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) {}
}
2025-02-24 12:39:42 -03:00
}