public static function createOverlappingDateRangeFilter(DateRange $range)
 {
     return function ($booking) use($range) {
         $bookingRange = new DateRange($booking->start, $booking->end);
         return $range->overlaps($bookingRange);
     };
 }
 public function process(Event $event, RuleConfig $config)
 {
     $entries = new ArrayCollection();
     $configRange = new DateRange($config->start, $config->end);
     $eventRange = new DateRange($event->start, $event->end);
     if ($configRange->isEmpty()) {
         return $entries;
     }
     $amountPerRange = new Money($config->amount, $config->currency);
     $configDays = (int) $configRange->getStart()->diff($configRange->getEnd())->format('%R%a') + 1;
     $totalDays = (int) $eventRange->getStart()->diff($eventRange->getEnd())->format('%R%a') + 1;
     // If we match up nicely, just bill at the fixed value and we're done
     if ($eventRange->equals($configRange)) {
         $rangeTotal = $amountPerRange;
         $entry = new Entry();
         $entry->amount = $rangeTotal->round(2);
         $entry->currency = $rangeTotal->getCurrency();
         $entry->code = $config->code;
         $entry->description = sprintf('%s to %s (%s %s) @ %s for the entire range', $event->start->format('Y-m-d'), $event->end->format('Y-m-d'), $totalDays, $totalDays == 1 ? 'day' : 'days', $amountPerRange->format());
         $entries->add($entry);
     } else {
         // (amount per fixed range / days in fixed range) * days billed
         $proratedTotal = $amountPerRange->div($configDays)->mul($totalDays);
         $entry = new Entry();
         $entry->amount = $proratedTotal->round(2);
         $entry->currency = $proratedTotal->getCurrency();
         $entry->code = $config->code;
         $entry->description = sprintf('%s to %s (%s %s) @ %s for part of %s to %s (%s %s) (prorated daily)', $event->start->format('Y-m-d'), $event->end->format('Y-m-d'), $totalDays, $totalDays == 1 ? 'day' : 'days', $amountPerRange->format(), $configRange->getStart()->format('Y-m-d'), $configRange->getEnd()->format('Y-m-d'), $configDays, $configDays == 1 ? 'day' : 'days');
         $entries->add($entry);
     }
     return $entries;
 }
 public function dataTableBookingSummary($bookings)
 {
     $ac = $this->_actionController;
     $actions = array('delete' => $ac->getAcl()->isAllowed('_user', 'facility_booking', 'write'), 'details' => $ac->getAcl()->isAllowed('_user', 'facility_booking', 'read'), 'edit' => $ac->getAcl()->isAllowed('_user', 'facility_booking', 'write'));
     $rows = array();
     foreach ($bookings as $booking) {
         $facility = $booking->facility;
         $bookingDateRange = new DateRange($booking->start, $booking->end);
         $rows[] = array('actions' => $actions, 'end' => $booking->end, 'id' => $booking->id, 'is_current' => $bookingDateRange->includes(new DateTime(date('Y-m-d'))), 'name' => implode(' ', $facility->getNamesOnDate($booking->start)), 'start' => $booking->start, 'uri' => $ac->getHelper('Url')->direct('view', 'facility', 'facility', array('id' => $facility->id)), 'delete_uri' => $ac->getHelper('Url')->direct('index', 'delete', 'booking', array('id' => $booking->id)), 'details_uri' => $ac->getHelper('Url')->direct('view', 'index', 'booking', array('id' => $booking->id)), 'edit_uri' => $ac->getHelper('Url')->direct('index', 'edit', 'booking', array('id' => $booking->id)));
     }
     return $rows;
 }
 protected function buildingConfiguration($facilityGroup)
 {
     $ac = $this->_actionController;
     $view = $ac->view;
     $actions = array('delete' => $ac->getAcl()->isAllowed('_user', 'facility', 'write'), 'edit' => $ac->getAcl()->isAllowed('_user', 'facility', 'write'));
     $rows = array();
     foreach ($facilityGroup->configs as $config) {
         $dateRange = new DateRange($config->start, $config->end);
         $row = array('actions' => $actions, 'id' => $config->id, 'is_current' => $dateRange->includes(new DateTime(date('Y-m-d'))), 'name' => $config->name, 'gender' => $config->gender, 'start' => $config->start ?: new DateTime('1900-01-01'), 'end' => $config->end ?: new DateTime('2099-01-01'), 'delete_uri' => $view->url(array('module' => 'facility', 'controller' => 'facilitygroupconfig', 'action' => 'delete', 'id' => $config->id), null, true), 'edit_uri' => $view->url(array('module' => 'facility', 'controller' => 'facilitygroupconfig', 'action' => 'edit', 'id' => $config->id), null, true));
         $rows[] = $row;
     }
     return $rows;
 }
 protected function roomConfiguration($facility)
 {
     $ac = $this->_actionController;
     $view = $ac->view;
     $actions = array('copy' => $ac->getAcl()->isAllowed('_user', 'facility', 'write'), 'delete' => $ac->getAcl()->isAllowed('_user', 'facility', 'write'), 'edit' => $ac->getAcl()->isAllowed('_user', 'facility', 'write'));
     $rows = array();
     foreach ($facility->configs as $config) {
         $dateRange = new DateRange($config->start, $config->end);
         $row = array('actions' => $actions, 'id' => $config->id, 'is_current' => $dateRange->includes(new DateTime(date('Y-m-d'))), 'name' => $config->name, 'type' => $config->type->name, 'floor' => $config->floor, 'section' => $config->section, 'capacity' => $config->capacity, 'gender' => $config->gender, 'start' => $config->start ?: new DateTime('1900-01-01'), 'end' => $config->end ?: new DateTime('2099-01-01'), 'suite' => $config->suite, 'note' => $config->note, 'default_billing_rule' => $config->default_billing_rule ? $config->default_billing_rule->description : '', 'tags' => $config->tags, 'delete_uri' => $view->url(array('module' => 'facility', 'controller' => 'facilityconfig', 'action' => 'delete', 'id' => $config->id), null, true), 'edit_uri' => $view->url(array('module' => 'facility', 'controller' => 'facilityconfig', 'action' => 'edit', 'id' => $config->id), null, true), 'copy_uri' => $view->url(array('module' => 'facility', 'controller' => 'facilityconfig', 'action' => 'copy', 'id' => $config->id), null, true));
         $rows[] = $row;
     }
     return $rows;
 }
 /**
  * Get last matching rule configuration.
  */
 protected function getMatchingConfiguration($rule, DateTime $date)
 {
     $overlapFilter = function ($config) use($date) {
         $configRange = new DateRange($config->start, $config->end);
         return $configRange->includes($date);
     };
     $overlappingConfigs = $rule->configs->filter($overlapFilter);
     if (count($overlappingConfigs) === 0) {
         throw new Exception\RuntimeException(sprintf('Could not find a rule configuration valid on %s' . ' for rule %s.', $date->format('Y-m-d'), $rule->id));
     }
     // Ordering is guaranteed by the Entity collection specification and
     // preserved by ArrayCollection#filter.
     return $overlappingConfigs->last();
 }
 public function dataTableMealplanDetail($bookings)
 {
     $ac = $this->_actionController;
     $view = $ac->view;
     if (count($bookings) === 0) {
         return array();
     }
     $actions = array('delete' => $ac->getAcl()->isAllowed('_user', 'mealplan_booking', 'write'), 'details' => $ac->getAcl()->isAllowed('_user', 'mealplan_booking', 'read'), 'edit' => $ac->getAcl()->isAllowed('_user', 'mealplan_booking', 'write'));
     $rows = array();
     foreach ($bookings as $booking) {
         $bookingDateRange = new DateRange($booking->start, $booking->end);
         $rows[] = array('actions' => $actions, 'created_at' => $booking->created_at, 'created_by' => $booking->created_by, 'updated_at' => $booking->updated_at, 'updated_by' => $booking->updated_by, 'end' => $booking->end, 'note' => $booking->note, 'id' => $booking->id, 'is_current' => $bookingDateRange->includes(new DateTime(date('Y-m-d'))), 'name' => $view->escape($booking->mealplan->name), 'start' => $booking->start, 'delete_uri' => $view->url(array('module' => 'mealplan', 'controller' => 'delete', 'action' => 'index', 'id' => $booking->id), null, true), 'details_uri' => $view->url(array('module' => 'mealplan', 'controller' => 'index', 'action' => 'view', 'id' => $booking->id), null, true), 'edit_uri' => $view->url(array('module' => 'mealplan', 'controller' => 'edit', 'action' => 'index', 'id' => $booking->id), null, true));
     }
     return $rows;
 }
 public function dataTableContractSummary($signatures)
 {
     $ac = $this->_actionController;
     $view = $ac->view;
     if (count($signatures) === 0) {
         return array();
     }
     $actions = array('edit' => $ac->getAcl()->isAllowed('_user', 'contract', 'write'));
     $rows = array();
     foreach ($signatures as $signature) {
         $contract = $signature->contract;
         $contractDateRange = new DateRange($contract->start, $contract->end);
         $rows[] = array('actions' => $actions, 'contract' => $contract->name, 'id' => $signature->id, 'is_cancelled' => $signature->is_cancelled, 'is_cosigned' => $signature->is_cosigned, 'is_current' => $contractDateRange->includes(new DateTime(date('Y-m-d'))), 'is_signed' => $signature->is_signed, 'requires_cosigned' => $signature->requires_cosigned, 'signed_at' => $signature->signed_at, 'edit_uri' => $view->url(array('module' => 'contract', 'controller' => 'signature', 'action' => 'edit', 'id' => $signature->id), null, true));
     }
     return $rows;
 }
 public function dataTableFacilityBooking($facility)
 {
     $ac = $this->_actionController;
     $view = $ac->view;
     if (count($facility->bookings) === 0) {
         return array();
     }
     $actions = array('delete' => $ac->getAcl()->isAllowed('_user', 'facility_booking', 'write'), 'details' => $ac->getAcl()->isAllowed('_user', 'facility_booking', 'read'), 'edit' => $ac->getAcl()->isAllowed('_user', 'facility_booking', 'write'));
     $rows = array();
     foreach ($facility->bookings as $booking) {
         $bookingDateRange = new DateRange($booking->start, $booking->end);
         $row = array('actions' => $actions, 'id' => $booking->id, 'is_current' => $bookingDateRange->includes(new DateTime(date('Y-m-d'))), 'person_uri' => $ac->getHelper('Url')->direct('view', 'person', 'person', array('id' => $booking->person->id)), 'person_name' => $view->escape($booking->person->display_name), 'person_gender' => $booking->person->gender, 'start' => $booking->start ?: new DateTime('1900-01-01'), 'end' => $booking->end ?: new DateTime('2099-01-01'), 'delete_uri' => $view->url(array('module' => 'booking', 'controller' => 'delete', 'action' => 'index', 'id' => $booking->id), null, true), 'details_uri' => $view->url(array('module' => 'booking', 'controller' => 'index', 'action' => 'view', 'id' => $booking->id), null, true), 'edit_uri' => $view->url(array('module' => 'booking', 'controller' => 'edit', 'action' => 'index', 'id' => $booking->id), null, true));
         $rows[] = $row;
     }
     return $rows;
 }
 public function dataTableFacilityHold($facility)
 {
     $ac = $this->_actionController;
     $view = $ac->view;
     if (count($facility->holds) === 0) {
         return array();
     }
     $actions = array('delete' => $ac->getAcl()->isAllowed('_user', 'facility', 'write'), 'edit' => $ac->getAcl()->isAllowed('_user', 'facility', 'write'));
     $rows = array();
     foreach ($facility->holds as $hold) {
         $holdDateRange = new DateRange($hold->start, $hold->end);
         $row = array('actions' => $actions, 'start' => $hold->start ?: new DateTime('1000-01-01'), 'end' => $hold->end ?: new DateTime('9999-01-01'), 'description' => isset($hold->description) ? $view->escape($hold->description) : '', 'gender' => $hold->gender ?: 'U', 'id' => $hold->id, 'is_current' => $holdDateRange->includes(new DateTime(date('Y-m-d'))), 'space' => $hold->space ?: 0, 'delete_uri' => $view->url(array('module' => 'facility', 'controller' => 'hold', 'action' => 'delete', 'id' => $hold->id), null, true), 'edit_uri' => $view->url(array('module' => 'facility', 'controller' => 'hold', 'action' => 'edit', 'id' => $hold->id), null, true));
         $rows[] = $row;
     }
     return $rows;
 }
 /**
  * @param  Event   $event
  * @return Entry[]
  *
  * @throws Exception\RuntimeException
  * @throws Zend\Di\Exception\ClassNotFoundException
  */
 public function process(Event $event)
 {
     $entries = new ArrayCollection();
     $eventRange = new DateRange($event->start, $event->end);
     if ($eventRange->isEmpty()) {
         return $entries;
     }
     $rule = $event->rule;
     if ($rule === null) {
         throw new Exception\RuntimeException(sprintf('The event %s has no associated rule.', $event->id));
     }
     $config = $this->getMatchingConfiguration($rule, $eventRange->getStart());
     if ($config->end < $eventRange->getEnd()) {
         throw new Exception\RuntimeException(sprintf('The rule configuration %s from %s to %s does not' . ' cover the desired range %s to %s.', $config->id, $config->start->format('Y-m-d'), $config->end->format('Y-m-d'), $eventRange->getStart()->format('Y-m-d'), $eventRange->getEnd()->format('Y-m-d')));
     }
     $strategy = $this->di->get($config->strategy);
     if (!$strategy instanceof StrategyInterface) {
         throw new Exception\RuntimeException(sprintf('The class %s does not implement %s.', get_class($strategy), 'Tillikum\\Billing\\Event\\Strategy\\StrategyInterface'));
     }
     $strategyEntries = $strategy->process($event, $config);
     foreach ($strategyEntries as $entry) {
         if ($event->is_credit) {
             $entry->amount *= -1;
         }
         $entries->add($entry);
     }
     return $entries;
 }
Example #12
0
 public function process(Event $event, RuleConfig $config)
 {
     $entries = new ArrayCollection();
     $eventRange = new DateRange($event->start, $event->end);
     // Days: Day difference + 1
     $totalDays = (int) $eventRange->getStart()->diff($eventRange->getEnd())->format('%R%a') + 1;
     // The total number of full weeks
     $weeks = (int) floor($totalDays / 7);
     // The number of leftover days after full weeks are counted
     $leftoverDays = (int) $totalDays % 7;
     $amountPerWeek = new Money($config->amount, $config->currency);
     // amount per week * number of weeks
     $weekTotal = $amountPerWeek->mul($weeks);
     // (amount per week / 7) * leftover days (prorate)
     $leftoverDayTotal = $amountPerWeek->div(7)->mul($leftoverDays);
     // If we have solid weeks, make an entry for that total
     if ($weeks > 0) {
         $fullWeekEndDate = clone $eventRange->getEnd();
         $fullWeekEndDate->modify("-{$leftoverDays} day");
         $entry = new entry();
         $entry->amount = $weekTotal->round(2);
         $entry->currency = $weekTotal->getCurrency();
         $entry->code = $config->code;
         $entry->description = sprintf('%s to %s (%s %s) @ %s per week', $eventRange->getStart()->format('Y-m-d'), $fullWeekEndDate->format('Y-m-d'), $weeks, $weeks == 1 ? 'week' : 'weeks', $amountPerWeek->format());
         $entries->add($entry);
     }
     if ($leftoverDays > 0) {
         // Start 1 day after the end of the previous full week(s), if there
         // were any
         $partialWeekStartDate = clone $eventRange->getEnd();
         $partialWeekStartDate->modify("-{$leftoverDays} day")->modify('+1 day');
         $entry = new Entry();
         $entry->amount = $leftoverDayTotal->round(2);
         $entry->currency = $leftoverDayTotal->getCurrency();
         $entry->code = $config->code;
         $entry->description = sprintf('%s to %s (%s %s) @ %s per week (prorated daily)', $partialWeekStartDate->format('Y-m-d'), $eventRange->getEnd()->format('Y-m-d'), $leftoverDays, $leftoverDays == 1 ? 'day' : 'days', $amountPerWeek->format());
         $entries->add($entry);
     }
     return $entries;
 }
Example #13
0
 /**
  * Test whether this DateRange overlaps the current DateRange
  *
  * @param  DateRange $arg Other DateRange to test
  * @return bool
  */
 public function overlaps(DateRange $arg)
 {
     return $arg->includes($this->getStart()) || $arg->includes($this->getEnd()) || $this->includes($arg);
 }
Example #14
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;
 }
 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;
 }
 /**
  * Get the configuration valid on the given date, if any.
  *
  * @param  DateTime           $date Date to test configurations against
  * @return Config\Config|null Configuration on the passed date
  */
 public function getConfigOnDate(DateTime $date)
 {
     foreach ($this->configs as $config) {
         $configRange = new DateRange($config->start, $config->end);
         if ($configRange->includes($date)) {
             return $config;
         }
     }
     return null;
 }
 /**
  * Get the hold valid on the given date, if any
  *
  * @return Hold\Hold|null
  */
 public function getHoldOnDate(DateTime $date)
 {
     $ret = $this->holds->filter(function ($hold) use($date) {
         $holdRange = new DateRange($hold->start, $hold->end);
         return $holdRange->includes($date);
     })->first();
     return $ret === false ? null : $ret;
 }
Example #18
0
 public function testIsFutureIsPastIsInfinite()
 {
     $dr1 = new DateRange(new DateTime('2006-09-06'), new DateTime('2006-09-15'));
     $dr2 = new DateRange(new DateTime(DateRange::PAST), new DateTime('2006-09-15'));
     $dr3 = new DateRange(new DateTime('2006-09-06'), new DateTime(DateRange::FUTURE));
     $dr4 = new DateRange(new DateTime(DateRange::PAST), new DateTime(DateRange::FUTURE));
     $this->assertFalse($dr1->isPast(), $dr1->__toString());
     $this->assertFalse($dr1->isFuture(), $dr1->__toString());
     $this->assertFalse($dr1->isInfinite(), $dr1->__toString());
     $this->assertTrue($dr2->isPast(), $dr2->__toString());
     $this->assertFalse($dr2->isFuture(), $dr2->__toString());
     $this->assertFalse($dr2->isInfinite(), $dr2->__toString());
     $this->assertFalse($dr3->isPast(), $dr3->__toString());
     $this->assertTrue($dr3->isFuture(), $dr3->__toString());
     $this->assertFalse($dr3->isInfinite(), $dr3->__toString());
     $this->assertTrue($dr4->isPast(), $dr4->__toString());
     $this->assertTrue($dr4->isFuture(), $dr4->__toString());
     $this->assertTrue($dr4->isInfinite(), $dr4->__toString());
 }