public function testSuccessWhenIncreaseAndDecreaseAreTheSameDate()
 {
     $inputs = array(new Occupancy\Input(new DateTime('2010-01-01'), 1, 'config 1 start'), new Occupancy\Input(new DateTime('2010-01-01'), -1, 'booking 1 start'), new Occupancy\Input(new DateTime('2010-01-10'), 1, 'booking 1 end'), new Occupancy\Input(new DateTime('2010-01-10'), -1, 'booking 2 start'), new Occupancy\Input(new DateTime('2010-01-20'), 1, 'booking 2 end'));
     $e = new Occupancy\Engine($inputs);
     $result = $e->run();
     $this->assertTrue($result->getIsSuccess());
 }
Example #2
0
 public function isValid($data)
 {
     if (!parent::isValid($data)) {
         return false;
     }
     $startDate = new DateTime($data['start']);
     $endDate = new DateTime($data['end']);
     if ($startDate > $endDate) {
         $this->start->addError($this->getTranslator()->translate('The start date must be on or before the end date.'));
         $this->end->addError($this->getTranslator()->translate('The end date must be on or after the start date.'));
         return false;
     }
     $facility = $this->em->find('Tillikum\\Entity\\Facility\\Facility', $data['facility_id']);
     $holdQueryBuilder = $this->em->createQueryBuilder()->select('h')->from('Tillikum\\Entity\\Facility\\Hold\\Hold', 'h')->where('h.start <= :proposedEnd')->andWhere('h.end >= :proposedStart')->andWhere('h.facility = :facility')->orderBy('h.start')->setParameter('facility', $facility)->setParameter('proposedStart', $startDate)->setParameter('proposedEnd', $endDate);
     if ($this->entity && isset($this->entity->id)) {
         $holdQueryBuilder->andWhere('h != :entity')->setParameter('entity', $this->entity);
     }
     $holds = $holdQueryBuilder->getQuery()->getResult();
     $bookings = $this->em->createQueryBuilder()->select('b')->from('Tillikum\\Entity\\Booking\\Facility\\Facility', 'b')->where('b.start <= :proposedEnd')->andWhere('b.end >= :proposedStart')->andWhere('b.facility = :facility')->orderBy('b.start')->setParameter('facility', $facility)->setParameter('proposedStart', $startDate)->setParameter('proposedEnd', $endDate)->getQuery()->getResult();
     $configs = $this->em->createQueryBuilder()->select('c')->from('Tillikum\\Entity\\Facility\\Config\\Config', 'c')->where('c.facility = :facility')->orderBy('c.start')->setParameter('facility', $facility)->getQuery()->getResult();
     if (count($holds) > 0) {
         foreach ($holds as $hold) {
             $errorMessage = sprintf($this->getTranslator()->translate('An existing hold from %s to %s overlaps your intended hold.'), $hold->start->format('Y-m-d'), $hold->end->format('Y-m-d'));
             $this->start->addError($errorMessage);
             $this->end->addError($errorMessage);
         }
         return false;
     }
     $occupancyInputs = array(new OccupancyInput($startDate, $data['space'] * -1, sprintf('start of the hold you specified from %s to %s', $startDate->format('Y-m-d'), $endDate->format('Y-m-d'))), new OccupancyInput(date_modify(clone $endDate, '+1 day'), $data['space'], sprintf('end of the hold you specified from %s to %s', $startDate->format('Y-m-d'), $endDate->format('Y-m-d'))));
     foreach ($bookings as $booking) {
         $occupancyInputs[] = new OccupancyInput($booking->start, -1, sprintf('start of a booking from %s to %s', $booking->start->format('Y-m-d'), $booking->end->format('Y-m-d')));
         $occupancyInputs[] = new OccupancyInput(date_modify(clone $booking->end, '+1 day'), 1, sprintf('end of a booking from %s to %s', $booking->start->format('Y-m-d'), $booking->end->format('Y-m-d')));
     }
     $currentConfigSpace = 0;
     foreach ($configs as $config) {
         $occupancyInputs[] = new OccupancyInput($config->start, $config->capacity - $currentConfigSpace, sprintf('start of a facility configuration from %s to %s', $config->start->format('Y-m-d'), $config->end->format('Y-m-d')));
         $currentConfigSpace = $config->capacity;
     }
     foreach ($holds as $hold) {
         $occupancyInputs[] = new OccupancyInput($hold->start, $hold->space * -1, sprintf('start of a hold from %s to %s', $hold->start->format('Y-m-d'), $hold->end->format('Y-m-d')));
         $occupancyInputs[] = new OccupancyInput(date_modify(clone $hold->end, '+1 day'), $hold->space, sprintf('end of a hold from %s to %s', $hold->start->format('Y-m-d'), $hold->end->format('Y-m-d')));
     }
     $occupancyEngine = new OccupancyEngine($occupancyInputs);
     $occupancyResult = $occupancyEngine->run();
     if (!$occupancyResult->getIsSuccess()) {
         $errorMessage = sprintf($this->getTranslator()->translate('There is no available space in this facility to add another ' . 'hold during the specified time period. The problem occurred ' . 'at the %s.'), $occupancyResult->getCulprit()->getDescription());
         $this->start->addError($errorMessage);
         $this->end->addError($errorMessage);
         return false;
     }
     return true;
 }
 public function isValid($data)
 {
     if (!parent::isValid($data)) {
         return false;
     }
     if ($this->isArray()) {
         $data = $this->_dissolveArrayValue($data, $this->getElementsBelongTo());
     }
     $startDate = new DateTime($data['start']);
     $endDate = new DateTime($data['end']);
     if ($startDate > $endDate) {
         $this->start->addError($this->getTranslator()->translate('The start date must be on or before the end date.'));
         $this->end->addError($this->getTranslator()->translate('The end date must be on or after the start date.'));
         return false;
     }
     $bookingRange = new DateRange($startDate, $endDate);
     $bookingFacility = $this->em->find('Tillikum\\Entity\\Facility\\Facility', $data['facility_id']);
     $person = $this->booking->person;
     $bookings = $this->em->createQueryBuilder()->select('b')->from('Tillikum\\Entity\\Booking\\Facility\\Facility', 'b')->where('b.start <= :proposedEnd')->andWhere('b.end >= :proposedStart')->andWhere('b.facility = :facility')->andWhere('b.person != :person')->orderBy('b.start')->setParameter('facility', $bookingFacility)->setParameter('person', $person)->setParameter('proposedStart', $bookingRange->getStart())->setParameter('proposedEnd', $bookingRange->getEnd())->getQuery()->getResult();
     $configs = $this->em->createQueryBuilder()->select('c')->from('Tillikum\\Entity\\Facility\\Config\\Config', 'c')->where('c.facility = :facility')->orderBy('c.start')->setParameter('facility', $bookingFacility)->getQuery()->getResult();
     $holds = $this->em->createQueryBuilder()->select('h')->from('Tillikum\\Entity\\Facility\\Hold\\Hold', 'h')->where('h.start <= :proposedEnd')->andWhere('h.end >= :proposedStart')->andWhere('h.facility = :facility')->orderBy('h.start')->setParameter('facility', $bookingFacility)->setParameter('proposedStart', $bookingRange->getStart())->setParameter('proposedEnd', $bookingRange->getEnd())->getQuery()->getResult();
     $occupancyInputs = array(new OccupancyInput($bookingRange->getStart(), -1, sprintf('start of the booking range you specified from %s to %s', $bookingRange->getStart()->format('Y-m-d'), $bookingRange->getEnd()->format('Y-m-d'))), new OccupancyInput(date_modify(clone $bookingRange->getEnd(), '+1 day'), 1, sprintf('end of the booking range you specified from %s to %s', $bookingRange->getStart()->format('Y-m-d'), $bookingRange->getEnd()->format('Y-m-d'))));
     foreach ($bookings as $booking) {
         $occupancyInputs[] = new OccupancyInput($booking->start, -1, sprintf('start of a booking from %s to %s', $booking->start->format('Y-m-d'), $booking->end->format('Y-m-d')));
         $occupancyInputs[] = new OccupancyInput(date_modify(clone $booking->end, '+1 day'), 1, sprintf('end of a booking from %s to %s', $booking->start->format('Y-m-d'), $booking->end->format('Y-m-d')));
         if (!empty($booking->person->gender)) {
             $bookingGenderSpec = isset($bookingGenderSpec) ? $bookingGenderSpec->andSpec(new GenderMatchSpecification($booking->person->gender)) : new GenderMatchSpecification($booking->person->gender);
         }
     }
     $currentConfigSpace = 0;
     foreach ($configs as $config) {
         $occupancyInputs[] = new OccupancyInput($config->start, $config->capacity - $currentConfigSpace, sprintf('start of a facility configuration from %s to %s', $config->start->format('Y-m-d'), $config->end->format('Y-m-d')));
         $currentConfigSpace = $config->capacity;
         if (!empty($config->gender)) {
             $facilityGenderSpec = isset($facilityGenderSpec) ? $facilityGenderSpec->andSpec(new GenderMatchSpecification($config->gender)) : new GenderMatchSpecification($config->gender);
         }
         if (!empty($config->suite)) {
             $suiteConfigs = $this->em->createQueryBuilder()->select('c')->from('Tillikum\\Entity\\Facility\\Config\\Room\\Room', 'c')->where('c.start <= :proposedEnd')->andWhere('c.end >= :proposedStart')->andWhere('c.suite = :suite')->setParameter('proposedStart', $bookingRange->getStart())->setParameter('proposedEnd', $bookingRange->getEnd())->setParameter('suite', $config->suite)->getQuery()->getResult();
             foreach ($suiteConfigs as $suiteConfig) {
                 if (!empty($suiteConfig->gender)) {
                     $suiteGenderSpec = isset($suiteGenderSpec) ? $suiteGenderSpec->andSpec(new GenderMatchSpecification($suiteConfig->gender)) : new GenderMatchSpecification($suiteConfig->gender);
                 }
             }
         }
     }
     foreach ($holds as $hold) {
         $occupancyInputs[] = new OccupancyInput($hold->start, $hold->space * -1, sprintf('start of a hold from %s to %s', $hold->start->format('Y-m-d'), $hold->end->format('Y-m-d')));
         $occupancyInputs[] = new OccupancyInput(date_modify(clone $hold->end, '+1 day'), $hold->space, sprintf('end of a hold from %s to %s', $hold->start->format('Y-m-d'), $hold->end->format('Y-m-d')));
         if (!empty($hold->gender)) {
             $holdGenderSpec = isset($holdGenderSpec) ? $holdGenderSpec->andSpec(new GenderMatchSpecification($hold->gender)) : new GenderMatchSpecification($hold->gender);
         }
     }
     $occupancyEngine = new OccupancyEngine($occupancyInputs);
     $occupancyResult = $occupancyEngine->run();
     if (!$occupancyResult->getIsSuccess()) {
         $this->facility_name->addError(sprintf($this->getTranslator()->translate('There is no available space in this facility to book another' . ' resident during the specified time period. The problem' . ' occurred at the %s.'), $occupancyResult->getCulprit()->getDescription()));
         return false;
     }
     if (isset($bookingGenderSpec) && !$bookingGenderSpec->isSatisfiedBy($person->gender)) {
         $this->addWarning(sprintf($this->getTranslator()->translate('The person you are booking with gender %s did not meet' . ' the gender requirements of the other people booked' . ' to this facility for the desired time period.'), $person->gender));
     }
     if (isset($facilityGenderSpec) && !$facilityGenderSpec->isSatisfiedBy($person->gender)) {
         $this->addWarning(sprintf($this->getTranslator()->translate('The person you are booking with gender %s did not meet' . ' the gender requirements of the configurations for this' . ' facility for the desired time period.'), $person->gender));
     }
     if (isset($holdGenderSpec) && !$holdGenderSpec->isSatisfiedBy($person->gender)) {
         $this->addWarning(sprintf($this->getTranslator()->translate('The person you are booking with gender %s did not meet' . ' the gender requirements of the holds on this facility' . ' for the desired time period.'), $person->gender));
     }
     if (isset($suiteGenderSpec) && !$suiteGenderSpec->isSatisfiedBy($person->gender)) {
         $this->addWarning(sprintf($this->getTranslator()->translate('The person you are booking with gender %s did not meet' . ' the gender requirements of the other people booked to' . ' this suite for the specified time period.'), $person->gender));
     }
     return true;
 }
Example #4
0
 public function isValid($data)
 {
     if (!parent::isValid($data)) {
         return false;
     }
     $startDate = new DateTime($data['start']);
     $endDate = new DateTime($data['end']);
     if ($startDate > $endDate) {
         $this->start->addError($this->getTranslator()->translate('The start date must be on or before the end date.'));
         $this->end->addError($this->getTranslator()->translate('The end date must be on or after the start date.'));
         return false;
     }
     $configRange = new DateRange($startDate, $endDate);
     $facility = $this->em->find('Tillikum\\Entity\\Facility\\Facility', $data['facility_id']);
     $bookings = $this->em->createQueryBuilder()->select('b')->from('Tillikum\\Entity\\Booking\\Facility\\Facility', 'b')->where('b.start <= :proposedEnd')->andWhere('b.end >= :proposedStart')->andWhere('b.facility = :facility')->orderBy('b.start')->setParameter('facility', $facility)->setParameter('proposedStart', $configRange->getStart())->setParameter('proposedEnd', $configRange->getEnd())->getQuery()->getResult();
     $qb = $this->em->createQueryBuilder()->select('c')->from('Tillikum\\Entity\\Facility\\Config\\Config', 'c')->where('c.facility = :facility')->orderBy('c.start')->setParameter('facility', $this->entity->facility);
     if ($this->entity && isset($this->entity->id)) {
         $qb->andWhere('c != :entity')->setParameter('entity', $this->entity);
     }
     $configs = $qb->getQuery()->getResult();
     $overlappingQueryBuilder = $this->em->createQueryBuilder()->select('c')->from('Tillikum\\Entity\\Facility\\Config\\Config', 'c')->where('c.start <= :proposedStart')->andWhere('c.end >= :proposedEnd')->andWhere('c.facility = :facility')->setParameter('proposedStart', $configRange->getStart())->setParameter('proposedEnd', $configRange->getEnd())->setParameter('facility', $this->entity->facility);
     if ($this->entity && isset($this->entity->id)) {
         $overlappingQueryBuilder->andWhere('c != :entity')->setParameter('entity', $this->entity);
     }
     $overlappingConfigs = $overlappingQueryBuilder->getQuery()->getResult();
     $holds = $this->em->createQueryBuilder()->select('h')->from('Tillikum\\Entity\\Facility\\Hold\\Hold', 'h')->where('h.start <= :proposedEnd')->andWhere('h.end >= :proposedStart')->andWhere('h.facility = :facility')->orderBy('h.start')->setParameter('facility', $facility)->setParameter('proposedStart', $configRange->getStart())->setParameter('proposedEnd', $configRange->getEnd())->getQuery()->getResult();
     if (count($overlappingConfigs) > 0) {
         foreach ($overlappingConfigs as $config) {
             $errorMessage = sprintf($this->getTranslator()->translate('An existing configuration from %s to %s overlaps your intended configuration.'), $config->start->format('Y-m-d'), $config->end->format('Y-m-d'));
             $this->start->addError($errorMessage);
             $this->end->addError($errorMessage);
         }
         return false;
     }
     $occupancyInputs = array(new OccupancyInput($configRange->getStart(), $data['capacity'], sprintf('start of the facility configuration you specified from %s to %s', $configRange->getStart()->format('Y-m-d'), $configRange->getEnd()->format('Y-m-d'))));
     foreach ($configs as $config) {
         $occupancyInputs[] = new OccupancyInput($config->start, $config->capacity, sprintf('start of a facility configuration from %s to %s', $config->start->format('Y-m-d'), $config->end->format('Y-m-d')));
         if (!empty($data['suite'])) {
             $suiteConfigs = $this->em->createQueryBuilder()->select('c')->from('Tillikum\\Entity\\Facility\\Config\\Room\\Room', 'c')->join('c.suite', 's')->where('c.start <= :proposedEnd')->andWhere('c.end >= :proposedStart')->andWhere('s.id = :suiteId')->setParameter('proposedStart', $configRange->getStart())->setParameter('proposedEnd', $configRange->getEnd())->setParameter('suiteId', $data['suite'])->getQuery()->getResult();
             foreach ($suiteConfigs as $suiteConfig) {
                 if (!empty($suiteConfig->gender)) {
                     $suiteGenderSpec = isset($suiteGenderSpec) ? $suiteGenderSpec->andSpec(new GenderMatchSpecification($suiteConfig->gender)) : new GenderMatchSpecification($suiteConfig->gender);
                 }
             }
         }
     }
     // We need to re-sort since the user-specified input will not be sorted
     usort($occupancyInputs, function ($a, $b) {
         if ($a->getDate() == $b->getDate()) {
             return 0;
         }
         return $a->getDate() < $b->getDate() ? -1 : 1;
     });
     // Actually calculate moments after re-sorting
     $currentConfigSpace = 0;
     foreach ($occupancyInputs as $idx => $input) {
         $oldValue = $input->getValue();
         $occupancyInputs[$idx] = new OccupancyInput($input->getDate(), $input->getValue() - $currentConfigSpace, $input->getDescription());
         $currentConfigSpace = $oldValue;
     }
     foreach ($bookings as $booking) {
         $occupancyInputs[] = new OccupancyInput($booking->start, -1, sprintf('start of a booking from %s to %s', $booking->start->format('Y-m-d'), $booking->end->format('Y-m-d')));
         $occupancyInputs[] = new OccupancyInput(date_modify(clone $booking->end, '+1 day'), 1, sprintf('end of a booking from %s to %s', $booking->start->format('Y-m-d'), $booking->end->format('Y-m-d')));
         if (!empty($booking->person->gender)) {
             $bookingGenderSpec = isset($bookingGenderSpec) ? $bookingGenderSpec->andSpec(new GenderMatchSpecification($booking->person->gender)) : new GenderMatchSpecification($booking->person->gender);
         }
     }
     foreach ($holds as $hold) {
         $occupancyInputs[] = new OccupancyInput($hold->start, $hold->space * -1, sprintf('start of a hold from %s to %s', $hold->start->format('Y-m-d'), $hold->end->format('Y-m-d')));
         $occupancyInputs[] = new OccupancyInput(date_modify(clone $hold->end, '+1 day'), $hold->space, sprintf('end of a hold from %s to %s', $hold->start->format('Y-m-d'), $hold->end->format('Y-m-d')));
         if (!empty($hold->gender)) {
             $holdGenderSpec = isset($holdGenderSpec) ? $holdGenderSpec->andSpec(new GenderMatchSpecification($hold->gender)) : new GenderMatchSpecification($hold->gender);
         }
     }
     $occupancyEngine = new OccupancyEngine($occupancyInputs);
     $occupancyResult = $occupancyEngine->run();
     if (!$occupancyResult->getIsSuccess()) {
         $this->capacity->addError(sprintf($this->getTranslator()->translate('There are too many claims on space in this facility ' . 'to change the capacity of this configuration. The ' . 'problem occurred at the %s.'), $occupancyResult->getCulprit()->getDescription()));
         return false;
     }
     if (isset($holdGenderSpec) && !$holdGenderSpec->isSatisfiedBy($data['gender'])) {
         $this->addWarning(sprintf($this->getTranslator()->translate('The desired configuration gender does not meet the' . ' gender requirements of an overlapping facility hold.')));
     }
     if (isset($bookingGenderSpec) && !$bookingGenderSpec->isSatisfiedBy($data['gender'])) {
         $this->addWarning(sprintf($this->getTranslator()->translate('The desired configuration gender does not meet the' . ' gender requirements of an overlapping booking.')));
     }
     if (isset($suiteGenderSpec) && !$suiteGenderSpec->isSatisfiedBy($data['gender'])) {
         $this->addWarning(sprintf($this->getTranslator()->translate('The desired configuration gender does not meet the' . ' gender requirements of an overlapping booking in a' . ' related suite.')));
     }
     return true;
 }