/** * Ajax method to check whether various attributes are required on a given session * (used to prevent them being turned off when they are needed on the session). * * @throws Exception */ public function actionCheckRequired() { if (!($session = OphTrOperationbooking_Operation_Session::model()->findByPk(@$_POST['session_id']))) { throw new Exception('Session not found: ' . $_POST['session_id']); } Yii::app()->event->dispatch('start_batch_mode'); switch (@$_POST['type']) { case 'consultant': $criteria = new CDbCriteria(); $criteria->addInCondition('`t`.status_id', array(2, 4)); $criteria->addCondition('session.id = :sessionId and booking.booking_cancellation_date is null and `t`.consultant_required = :required'); $criteria->params[':sessionId'] = $session->id; $criteria->params[':required'] = 1; if (Element_OphTrOperationbooking_Operation::model()->with(array('booking' => array('with' => 'session')))->find($criteria)) { echo '1'; } else { echo '0'; } return; case 'paediatric': foreach ($session->activeBookings as $booking) { if ($booking->operation->event->episode->patient->isChild($session->date)) { echo '1'; return; } } echo '0'; return; case 'anaesthetist': $criteria = new CDbCriteria(); $criteria->addCondition('session.id = :sessionId and booking.booking_cancellation_date is null and `t`.anaesthetist_required = :required'); $criteria->addInCondition('`t`.status_id', array(2, 4)); $criteria->params[':sessionId'] = $session->id; $criteria->params[':required'] = 1; if (Element_OphTrOperationbooking_Operation::model()->with(array('booking' => array('with' => 'session')))->find($criteria)) { echo '1'; } else { echo '0'; } return; case 'general_anaesthetic': $criteria = new CDbCriteria(); $criteria->addCondition('session.id = :sessionId and booking.booking_cancellation_date is null and `t`.anaesthetic_type_id = :anaestheticType'); $criteria->addInCondition('`t`.status_id', array(2, 4)); $criteria->params[':sessionId'] = $session->id; $criteria->params[':anaestheticType'] = 5; if (Element_OphTrOperationbooking_Operation::model()->with(array('booking' => array('with' => 'session')))->find($criteria)) { echo '1'; } else { echo '0'; } return; } throw new Exception('Unknown type: ' . @$_POST['type']); }
public function testAvailableProcedureCountNoMax() { $test = new OphTrOperationbooking_Operation_Session(); $this->assertNull($test->getAvailableProcedureCount()); }
protected function beforeValidate() { if ($this->start_date && !preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/', $this->start_date)) { $this->start_date = date('Y-m-d', strtotime($this->start_date)); } if ($this->end_date && !preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/', $this->end_date)) { $this->end_date = date('Y-m-d', strtotime($this->end_date)); } // Verify that this session doesn't conflict with any other sequences or sessions $criteria = new CDbCriteria(); if ($this->id) { $criteria->addCondition('id <> :id'); $criteria->params[':id'] = $this->id; } $criteria->addCondition('theatre_id = :theatre_id'); $criteria->params[':theatre_id'] = $this->theatre_id; $criteria->addCondition('weekday = :weekday'); $criteria->params[':weekday'] = $this->weekday; $criteria->addCondition('end_date is null or end_date >= :start_date'); $criteria->params[':start_date'] = $this->start_date; $dateList = $this->getDateListForMonths(12); $conflicts = array(); foreach (self::model()->findAll($criteria) as $sequence) { $s_dateList = $sequence->getDateListForMonths(12); foreach ($s_dateList as $date) { if (in_array($date, $dateList)) { $start = strtotime("{$date} {$this->start_time}"); $end = strtotime("{$date} {$this->end_time}"); $s_start = strtotime("{$date} {$sequence->start_time}"); $s_end = strtotime("{$date} {$sequence->end_time}"); if ($start < $s_end && $start >= $s_start) { if (!isset($conflicts[$sequence->id]['start_time'])) { $this->addError('start_time', "This start time conflicts with sequence {$sequence->id}"); $conflicts[$sequence->id]['start_time'] = 1; } } if ($end > $s_start && $end <= $s_end) { if (!isset($conflicts[$sequence->id]['end_time'])) { $this->addError('end_time', "This end time conflicts with sequence {$sequence->id}"); $conflicts[$sequence->id]['end_time'] = 1; } } if ($start < $s_start && $end > $s_end) { if (!isset($conflicts[$sequence->id]['end_time']) || !isset($conflicts[$sequence->id]['start_time'])) { $this->addError('start_time', "This start time conflicts with sequence {$sequence->id}"); $conflicts[$sequence->id]['start_time'] = 1; $this->addError('end_time', "This end time conflicts with sequence {$sequence->id}"); $conflicts[$sequence->id]['end_time'] = 1; } } } } } $criteria = new CDbCriteria(); $criteria->addCondition('sequence_id <> :sequence_id or sequence_id is null'); $criteria->params[':sequence_id'] = $this->id; $criteria->addCondition('theatre_id = :theatre_id'); $criteria->params[':theatre_id'] = $this->theatre_id; $criteria->addInCondition('date', $dateList); $conflicts = array(); foreach (OphTrOperationbooking_Operation_Session::model()->findAll($criteria) as $session) { $start = strtotime("{$session->date} {$this->start_time}"); $end = strtotime("{$session->date} {$this->end_time}"); $s_start = strtotime("{$session->date} {$session->start_time}"); $s_end = strtotime("{$session->date} {$session->end_time}"); if ($start < $s_end && $start >= $s_start) { if (!isset($conflicts[$session->id]['start_time'])) { $this->addError('start_time', "This start time conflicts with session {$session->id}"); $conflicts[$session->id]['start_time'] = 1; } } if ($end > $s_start && $end <= $s_end) { if (!isset($conflicts[$session->id]['end_time'])) { $this->addError('end_time', "This end time conflicts with session {$session->id}"); $conflicts[$session->id]['end_time'] = 1; } } if ($start < $s_start && $end > $s_end) { if (!isset($conflicts[$session->id]['end_time']) || !isset($conflicts[$session->id]['start_time'])) { $this->addError('start_time', "This start time conflicts with session {$session->id}"); $conflicts[$session->id]['start_time'] = 1; $this->addError('end_time', "This end time conflicts with session {$session->id}"); $conflicts[$session->id]['end_time'] = 1; } } } return parent::beforeValidate(); }
public function generateSessions($args = array()) { $output = ''; // Get sequences $today = date('Y-m-d'); $initialEndDate = empty($args) ? strtotime('+13 months') : strtotime($args[0]); $sequences = OphTrOperationbooking_Operation_Sequence::model()->findAll('start_date <= :end_date AND (end_date IS NULL or end_date >= :today)', array(':end_date' => date('Y-m-d', $initialEndDate), ':today' => $today)); foreach ($sequences as $sequence) { $criteria = new CDbCriteria(); $criteria->addCondition('sequence_id = :sequence_id'); $criteria->params[':sequence_id'] = $sequence->id; $criteria->order = 'date desc'; $session = OphTrOperationbooking_Operation_Session::model()->find($criteria); // The date of the most recent session for this sequence plus one day, or the sequence start date if no sessions for this sequence yet $startDate = empty($session) ? strtotime($sequence->start_date) : strtotime($session->date) + 60 * 60 * 24; // Sessions should be generated up to the smaller of initialEndDate (+13 months or command line) and sequence end_date if ($sequence->end_date && strtotime($sequence->end_date) < $initialEndDate) { $endDate = strtotime($sequence->end_date); } else { $endDate = $initialEndDate; } $dateList = array(); if ($sequence->interval_id == 1) { // NO REPEAT (single session) // If a session already exists for this one off there's no point creating another if (empty($session)) { $dateList[] = $sequence->start_date; } } elseif ($sequence->interval_id == 6 && $sequence->week_selection) { // MONTHLY REPEAT (weeks x,y of month) $date = date('Y-m-d', $startDate); $time = $startDate; // Get the next occurrence of the sequence on/after the start date while (date('N', $time) != date('N', strtotime($sequence->start_date))) { $date = date('Y-m-d', mktime(0, 0, 0, date('m', $time), date('d', $time) + 1, date('Y', $time))); $time = strtotime($date); } $dateList = $sequence->getWeekOccurrences($sequence->weekday, $sequence->week_selection, $time, $endDate, $date, date('Y-m-d', $endDate)); } else { // WEEKLY REPEAT (every x weeks) // There is a repeat interval, e.g. once every two weeks. In the instance of two weeks, the // function below returns 60 * 60 * 24 * 14, i.e. two weeks $interval = $sequence->interval->getInteger($endDate); // The number of days in the interval - 14 in the case of two week interval $days = $interval / 24 / 60 / 60; // IF there's no session use the sequence start date. If there is use the most recent // session date plus the interval (e.g. two weeks) if (empty($session)) { $nextStartDate = $startDate; } else { $nextStartDate = $startDate + $interval - 86400; } // Convert $nextStartDate (a timestamp of the seqence start date or the most recent session date plus the interval to a date. $date = date('Y-m-d', $nextStartDate); // The timestamp of the start date $time = $nextStartDate; // get the next occurrence of the sequence on/after the start date // Check to see if the day of the week for the time is the same day of the week as the sequence start date // Process loop if it isn't while (date('N', $time) != date('N', strtotime($sequence->start_date))) { // Set the date to $time + 1 day $date = date('Y-m-d', mktime(0, 0, 0, date('m', $time), date('d', $time) + 1, date('Y', $time))); // Set the time to the timstamp for the date + 1 day $time = strtotime($date); } while ($time <= $endDate) { $dateList[] = $date; $date = date('Y-m-d', mktime(0, 0, 0, date('m', $time), date('d', $time) + $days, date('Y', $time))); $time = strtotime($date); } } if (!empty($dateList)) { // Process dateList into sessions foreach ($dateList as $date) { // TODO: Check for collisions, maybe in Session validation code $new_session = new OphTrOperationbooking_Operation_Session(); foreach (array('start_time', 'end_time', 'consultant', 'anaesthetist', 'paediatric', 'general_anaesthetic', 'theatre_id', 'default_admission_time') as $attribute) { $new_session->{$attribute} = $sequence->{$attribute}; } $new_session->date = $date; $new_session->sequence_id = $sequence->id; $new_session->firm_id = $sequence->firm_id; if (Yii::app()->params['sessions_unavailable_past_date'] && $date >= Yii::app()->params['sessions_unavailable_past_date']) { $new_session->available = 0; } $new_session->save(); } $output .= "Sequence ID {$sequence->id}: Created " . count($dateList) . " session(s).\n"; } } if (!empty($args[1])) { return $output; } }
public function actionDeleteSessions() { if (!empty($_POST['session'])) { $criteria = new CDbCriteria(); $criteria->addInCondition('id', $_POST['session']); $sessions = OphTrOperationbooking_Operation_Session::model()->findAll($criteria); } elseif (@$_POST['use_filters']) { $sessions = $this->getSessions(true); } foreach ($sessions as $session) { if (!$session->delete()) { throw new Exception('Unable to delete session: ' . print_r($session->getErrors(), true)); } Audit::add('admin', 'delete', $session->id, null, array('module' => 'OphTrOperationbooking', 'model' => 'OphTrOperationbooking_Operation_Session')); } echo '1'; }
/** * Calculate the EROD for this operation - the firm used to determine the service can be overridden by providing a firm. * (Note that this handles the emergency list by having a firm placeholder object that does not have an id - at this time, * no sessions are assigned to A&E firms, having the effect that no EROD can be calculated for emergency bookings). * * @param Firm $firm * * @return OphTrOperationbooking_Operation_EROD|null * * @throws Exception */ public function calculateEROD($firm = null) { $criteria = new CDbCriteria(); $criteria->params[':one'] = 1; //consultant required if ($this->consultant_required) { $criteria->addCondition('`t`.consultant = :one'); } //anaesthetic requirements if ($this->anaesthetist_required || $this->anaesthetic_type->code == 'GA') { $criteria->addCondition('`t`.anaesthetist = :one and `t`.general_anaesthetic = :one'); } // child conditions $patient = $this->getPatient(); if ($patient->isChild()) { // need to get the point at which patient becomes an adult. All sessions up to that point need the pediatric flag $criteria->params[':adult_date'] = $patient->getBecomesAdultDate(); $criteria->addCondition('(`t`.date < :adult_date AND `t`.paediatric = :one) OR `t`.date >= :adult_date'); } // if their are firms that are set for the subspecialty of the episode, use their sessions if ($rule = OphTrOperationbooking_Operation_EROD_Rule::model()->find('subspecialty_id=?', array($this->getFirm()->getSubspecialtyID()))) { $firm_ids = array(); foreach ($rule->items as $item) { if ($item->item_type == 'firm') { $firm_ids[] = $item->item_id; } } $criteria->addInCondition('firm.id', $firm_ids); } else { // otherwise, use the given firm to define the set of valid sessions by subspecialty if (!$firm) { $firm = $this->event->episode->firm; } if (!$firm->id) { // booking into the emergency list if (!($subspecialty = Subspecialty::model()->find('ref_spec=?', array('AE')))) { throw new Exception('A&E subspecialty not found'); } if (!($service_subspecialty_assignment = ServiceSubspecialtyAssignment::model()->find('subspecialty_id=?', array($subspecialty->id)))) { throw new Exception('A&E service_subspecialty_assignment not found'); } $service_subspecialty_assignment_id = $service_subspecialty_assignment->id; } else { if (!($service_subspecialty_assignment_id = $firm->service_subspecialty_assignment_id)) { throw new Exception('Firm must have service_subspecialty_assignment for EROD calculation'); } } $criteria->addCondition('service_subspecialty_assignment_id = :serviceSubspecialtyAssignmentId'); $criteria->params[':serviceSubspecialtyAssignmentId'] = $service_subspecialty_assignment_id; } // session must be available $criteria->addCondition('`t`.available = :one'); // work out the lead date $lead_decision_date = strtotime($this->decision_date); if ($lead_weeks = Yii::app()->params['erod_lead_time_weeks']) { $lead_decision_date += 86400 * 7 * $lead_weeks; } $lead_current_date = time(); if ($lead_days = Yii::app()->params['erod_lead_current_date_days']) { $lead_current_date += 86400 * $lead_days; } $lead_time_date = $lead_decision_date > $lead_current_date ? date('Y-m-d', $lead_decision_date) : date('Y-m-d', $lead_current_date); $criteria->addCondition('`t`.date > :leadTimeDate'); $criteria->params[':leadTimeDate'] = $lead_time_date; $criteria->order = '`t`.date, `t`.start_time'; foreach (OphTrOperationbooking_Operation_Session::model()->with(array('firm' => array('joinType' => 'JOIN')))->findAll($criteria) as $session) { $available_time = $session->availableMinutes; if ($available_time < $this->total_duration) { continue; } if ($session->max_procedures > 0 && $this->getProcedureCount() > $session->getAvailableProcedureCount()) { continue; } $erod = new OphTrOperationbooking_Operation_EROD(); $erod->session_id = $session->id; $erod->session_date = $session->date; $erod->session_start_time = $session->start_time; $erod->session_end_time = $session->end_time; $erod->firm_id = $session->firm_id; $erod->consultant = $session->consultant; $erod->paediatric = $session->paediatric; $erod->anaesthetist = $session->anaesthetist; $erod->general_anaesthetic = $session->general_anaesthetic; $erod->session_duration = $session->duration; $erod->total_operations_time = $session->bookedMinutes; // Note that I have not subtracted the duration of this operation from the available time when storing this // as it is now being generated before the booking is made. When the booking is made, it will have been saved // before the EROD is calculated, so the available time will reflect the same value as in the prior calculations $erod->available_time = $available_time; return $erod; } }