2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM Community Edition is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
38 /*********************************************************************************
41 ********************************************************************************/
43 class Scheduler extends SugarBean {
49 var $modified_user_id;
52 var $modified_by_name;
66 var $intervalHumanReadable;
76 var $timeOutMins = 60;
77 // standard SugarBean attrs
78 var $table_name = "schedulers";
79 var $object_name = "schedulers";
80 var $module_dir = "Schedulers";
81 var $new_schema = true;
82 var $process_save_dates = true;
86 function Scheduler($init=true) {
90 //check is default admin exists
91 $adminId = $this->db->getOne(
92 'SELECT id FROM users WHERE id=\'1\' AND is_admin=1 AND deleted=0 AND status=\'Active\'',
94 'Error retrieving Admin account info'
96 if (false === $adminId) {//retrive another admin
97 $adminId = $this->db->getOne(
98 'SELECT id FROM users WHERE is_admin=1 AND deleted=0 AND status=\'Active\'',
100 'Error retrieving Admin account info'
103 $user->retrieve($adminId);
105 $GLOBALS['log']->fatal('No Admin account found!');
110 $user->retrieve('1'); // Scheduler jobs run as default Admin
117 ///////////////////////////////////////////////////////////////////////////
118 //// SCHEDULER HELPER FUNCTIONS
120 * executes Scheduled job
123 if(empty($this->job)) { // only execute when valid
124 $GLOBALS['log']->fatal('Scheduler tried to fire an empty job!!');
128 $exJob = explode('::', $this->job);
129 if(is_array($exJob)) {
130 // instantiate a new SchedulersJob object and prep it
133 $trackerManager = TrackerManager::getInstance();
134 $trackerManager->pause();
135 $job = new SchedulersJob();
136 $job->scheduler_id = $this->id;
137 $job->scheduler = $this;
138 $job->execute_time = $job->handleDateFormat('now');
139 $jobId = $job->save();
140 $trackerManager->unPause();
141 $job->retrieve($jobId);
143 if($exJob[0] == 'function') {
144 $GLOBALS['log']->debug('----->Scheduler found a job of type FUNCTION');
145 require_once('modules/Schedulers/_AddJobsHere.php');
150 $GLOBALS['log']->debug('----->SchedulersJob firing '.$func);
152 $res = call_user_func($func);
161 } elseif($exJob[0] == 'url') {
162 if(function_exists('curl_init')) {
163 $GLOBALS['log']->debug('----->SchedulersJob found a job of type URL');
166 $GLOBALS['log']->debug('----->SchedulersJob firing URL job: '.$exJob[1]);
167 if($job->fireUrl($exJob[1])) {
185 * flushes dead or hung jobs
187 function flushDeadJobs() {
188 $GLOBALS['log']->debug('-----> Scheduler flushing dead jobs');
190 $lowerLimit = mktime(0, 0, 0, 1, 1, 2005); // jan 01, 2005, GMT-0
191 $now = TimeDate::getInstance()->getNow()->ts; // current timestamp
193 $q = " SELECT s.id, s.name FROM schedulers s WHERE s.deleted=0 AND s.status = 'In Progress'";
194 $r = $this->db->query($q);
197 while($a = $this->db->fetchByAssoc($r)) {
198 $q2 = " SELECT st.id, st.execute_time FROM schedulers_times st
200 AND st.scheduler_id = '{$a['id']}'
201 ORDER BY st.execute_time DESC";
202 $r2 = $this->db->query($q2);
204 $a2 = $this->db->fetchByAssoc($r2); // we only care about the newest
205 $a2['execute_time'] = $this->db->fromConvert($a2['execute_time'],'datetime');
207 $GLOBALS['log']->debug("-----> Scheduler found [ {$a['name']} ] 'In Progress' with most recent Execute Time at [ {$a2['execute_time']} GMT-0 ]");
209 $execTime = TimeDate::getInstance()->fromDB($a2['execute_time'])->ts;
211 $GLOBALS['log']->debug("-----> Checking if Scheduler execTime ($execTime) is higher than lowerLimit ($lowerLimit)");
213 if($execTime > $lowerLimit) {
214 if(($now - $execTime) >= (60 * $this->timeOutMins)) {
215 $GLOBALS['log']->info("-----> Scheduler found a dead Job. Flushing status and reseting Job");
216 $q3 = "UPDATE schedulers SET status = 'Active' WHERE id = '{$a['id']}'";
217 $this->db->query($q3);
219 $GLOBALS['log']->info("-----> Scheduler setting Job Instance status to 'failed'");
220 $q4 = "UPDATE schedulers_times SET status = 'failed' WHERE id = '{$a2['id']}';";
221 $this->db->query($q4);
223 $GLOBALS['log']->debug("-----> Scheduler will wait for job to complete - not past threshold of [ ".($this->timeOutMins * 60)."secs ] - timeDiff is ".($now - $execTime)." secs");
226 $GLOBALS['log']->fatal("-----> Scheduler got a bad execute time: [ {$a2['execute_time']} GMT-0 ]");
236 * calculates if a job is qualified to run
238 function fireQualified() {
239 if(empty($this->id)) { // execute only if we have an instance
240 $GLOBALS['log']->fatal('Scheduler called fireQualified() in a non-instance');
244 $now = TimeDate::getInstance()->getNow();
245 $now = $now->setTime($now->hour, $now->min, "00")->asDb();
246 $validTimes = $this->deriveDBDateTimes($this);
248 if(is_array($validTimes) && in_array($now, $validTimes)) {
249 $GLOBALS['log']->debug('----->Scheduler found valid job ('.$this->name.') for time GMT('.$now.')');
252 $GLOBALS['log']->debug('----->Scheduler did NOT find valid job ('.$this->name.') for time GMT('.$now.')');
258 * Checks if any jobs qualify to run at this moment
260 function checkPendingJobs() {
261 $this->cleanJobLog();
262 $allSchedulers = $this->get_full_list('', 'schedulers.status=\'Active\'');
264 $GLOBALS['log']->info('-----> Scheduler found [ '.count($allSchedulers).' ] ACTIVE jobs');
266 if(!empty($allSchedulers)) {
267 foreach($allSchedulers as $focus) {
268 if($focus->fireQualified()) {
270 $GLOBALS['log']->debug('----->Scheduler Job completed successfully');
272 $GLOBALS['log']->fatal('----->Scheduler Job FAILED');
277 $GLOBALS['log']->debug('----->No Schedulers found');
282 * This function takes a Scheduler object and uses its job_interval
283 * attribute to derive DB-standard datetime strings, as many as are
284 * qualified by its ranges. The times are from the time of calling the
287 * @param $focus Scheduler object
288 * @return $dateTimes array loaded with DB datetime strings derived from
289 * the job_interval attribute
290 * @return false If we the Scheduler is not in scope, return false.
292 function deriveDBDateTimes($focus) {
294 $GLOBALS['log']->debug('----->Schedulers->deriveDBDateTimes() got an object of type: '.$focus->object_name);
295 /* [min][hr][dates][mon][days] */
296 $dateTimes = array();
297 $ints = explode('::', str_replace(' ','',$focus->job_interval));
303 $today = getdate($timedate->getNow()->ts);
307 $GLOBALS['log']->debug('----->got * day');
309 } elseif(strstr($days, '*/')) {
310 // the "*/x" format is nonsensical for this field
311 // do basically nothing.
312 $theDay = str_replace('*/','',$days);
313 $dayName[] = $theDay;
314 } elseif($days != '*') { // got particular day(s)
315 if(strstr($days, ',')) {
316 $exDays = explode(',',$days);
317 foreach($exDays as $k1 => $dayGroup) {
318 if(strstr($dayGroup,'-')) {
319 $exDayGroup = explode('-', $dayGroup); // build up range and iterate through
320 for($i=$exDayGroup[0];$i<=$exDayGroup[1];$i++) {
323 } else { // individuals
324 $dayName[] = $dayGroup;
327 } elseif(strstr($days, '-')) {
328 $exDayGroup = explode('-', $days); // build up range and iterate through
329 for($i=$exDayGroup[0];$i<=$exDayGroup[1];$i++) {
336 // check the day to be in scope:
337 if(!in_array(($today['wday']+6)%7, $dayName)) {//$dayName starts from Monday, while $today['wday'] starts from Sunday
345 // derive months part
347 $GLOBALS['log']->debug('----->got * months');
348 } elseif(strstr($mons, '*/')) {
349 $mult = str_replace('*/','',$mons);
350 $startMon = $timedate->fromDb(date_time_start)->month;
351 $startFrom = ($startMon % $mult);
353 for($i=$startFrom;$i<=12;$i+$mult) {
354 $compMons[] = $i+$mult;
357 // this month is not in one of the multiplier months
358 if(!in_array($today['mon'],$compMons)) {
361 } elseif($mons != '*') {
362 if(strstr($mons,',')) { // we have particular (groups) of months
363 $exMons = explode(',',$mons);
364 foreach($exMons as $k1 => $monGroup) {
365 if(strstr($monGroup, '-')) { // we have a range of months
366 $exMonGroup = explode('-',$monGroup);
367 for($i=$exMonGroup[0];$i<=$exMonGroup[1];$i++) {
371 $monName[] = $monGroup;
374 } elseif(strstr($mons, '-')) {
375 $exMonGroup = explode('-', $mons);
376 for($i=$exMonGroup[0];$i<=$exMonGroup[1];$i++) {
379 } else { // one particular month
383 // check that particular months are in scope
384 if(!in_array($today['mon'], $monName)) {
391 $GLOBALS['log']->debug('----->got * dates');
392 } elseif(strstr($dates, '*/')) {
393 $mult = str_replace('*/','',$dates);
394 $startDate = $timedate->fromDb($focus->date_time_start)->day;
395 $startFrom = ($startDate % $mult);
397 for($i=$startFrom; $i<=31; $i+$mult) {
398 $dateName[] = str_pad(($i+$mult),2,'0',STR_PAD_LEFT);
402 if(!in_array($today['mday'], $dateName)) {
405 } elseif($dates != '*') {
406 if(strstr($dates, ',')) {
407 $exDates = explode(',', $dates);
408 foreach($exDates as $k1 => $dateGroup) {
409 if(strstr($dateGroup, '-')) {
410 $exDateGroup = explode('-', $dateGroup);
411 for($i=$exDateGroup[0];$i<=$exDateGroup[1];$i++) {
415 $dateName[] = $dateGroup;
418 } elseif(strstr($dates, '-')) {
419 $exDateGroup = explode('-', $dates);
420 for($i=$exDateGroup[0];$i<=$exDateGroup[1];$i++) {
424 $dateName[] = $dates;
427 // check that dates are in scope
428 if(!in_array($today['mday'], $dateName)) {
434 //$currentHour = gmdate('G');
435 //$currentHour = date('G', strtotime('00:00'));
437 $GLOBALS['log']->debug('----->got * hours');
438 for($i=0;$i<24; $i++) {
441 } elseif(strstr($hrs, '*/')) {
442 $mult = str_replace('*/','',$hrs);
443 for($i=0; $i<24; $i) { // weird, i know
447 } elseif($hrs != '*') {
448 if(strstr($hrs, ',')) {
449 $exHrs = explode(',',$hrs);
450 foreach($exHrs as $k1 => $hrGroup) {
451 if(strstr($hrGroup, '-')) {
452 $exHrGroup = explode('-', $hrGroup);
453 for($i=$exHrGroup[0];$i<=$exHrGroup[1];$i++) {
457 $hrName[] = $hrGroup;
460 } elseif(strstr($hrs, '-')) {
461 $exHrs = explode('-', $hrs);
462 for($i=$exHrs[0];$i<=$exHrs[1];$i++) {
471 //$currentMin = date('i');
472 $currentMin = $timedate->getNow()->minute;
473 if(substr($currentMin, 0, 1) == '0') {
474 $currentMin = substr($currentMin, 1, 1);
477 $GLOBALS['log']->debug('----->got * mins');
478 for($i=0; $i<60; $i++) {
479 if(($currentMin + $i) > 59) {
480 $minName[] = ($i + $currentMin - 60);
482 $minName[] = ($i+$currentMin);
485 } elseif(strstr($mins,'*/')) {
486 $mult = str_replace('*/','',$mins);
487 $startMin = $timedate->fromDb($focus->date_time_start)->minute;
488 $startFrom = ($startMin % $mult);
489 for($i=$startFrom; $i<=59; $i) {
490 if(($currentMin + $i) > 59) {
491 $minName[] = ($i + $currentMin - 60);
493 $minName[] = ($i+$currentMin);
498 } elseif($mins != '*') {
499 if(strstr($mins, ',')) {
500 $exMins = explode(',',$mins);
501 foreach($exMins as $k1 => $minGroup) {
502 if(strstr($minGroup, '-')) {
503 $exMinGroup = explode('-', $minGroup);
504 for($i=$exMinGroup[0]; $i<=$exMinGroup[1]; $i++) {
508 $minName[] = $minGroup;
511 } elseif(strstr($mins, '-')) {
512 $exMinGroup = explode('-', $mins);
513 for($i=$exMinGroup[0]; $i<=$exMinGroup[1]; $i++) {
521 // prep some boundaries - these are not in GMT b/c gmt is a 24hour period, possibly bridging 2 local days
522 if(empty($focus->time_from) && empty($focus->time_to) ) {
524 $timeToTs = $timedate->getNow(true)->get('+1 day')->ts;
526 $tfrom = $timedate->fromDbType($focus->time_from, 'time');
527 $timeFromTs = $timedate->getNow(true)->setTime($tfrom->hour, $tfrom->min)->ts;
528 $tto = $timedate->fromDbType($focus->time_to, 'time');
529 $timeToTs = $timedate->getNow(true)->setTime($tto->hour, $tto->min)->ts;
533 if(empty($focus->last_run)) {
536 $lastRunTs = $timedate->fromDb($focus->last_run)->ts;
541 * initialize return array
543 $validJobTime = array();
546 $timeStartTs = $timedate->fromDb($focus->date_time_start)->ts;
547 if(!empty($focus->date_time_end)) { // do the same for date_time_end if not empty
548 $timeEndTs = $timedate->fromDb($focus->date_time_end)->ts;
550 $timeEndTs = $timedate->getNow(true)->get('+1 day')->ts;
551 // $dateTimeEnd = '2020-12-31 23:59:59'; // if empty, set it to something ridiculous
554 /*_pp('hours:'); _pp($hrName);_pp('mins:'); _pp($minName);*/
555 $dateobj = $timedate->getNow();
556 $nowTs = $dateobj->ts;
557 $GLOBALS['log']->debug(sprintf("Constraints: start: %s from: %s end: %s to: %s now: %s",
558 gmdate('Y-m-d H:i:s', $timeStartTs), gmdate('Y-m-d H:i:s', $timeFromTs), gmdate('Y-m-d H:i:s', $timeEndTs),
559 gmdate('Y-m-d H:i:s', $timeToTs), $timedate->nowDb()
561 // _pp('currentHour: '. $currentHour);
562 // _pp('timeStartTs: '.date('r',$timeStartTs));
563 // _pp('timeFromTs: '.date('r',$timeFromTs));
564 // _pp('timeEndTs: '.date('r',$timeEndTs));
565 // _pp('timeToTs: '.date('r',$timeToTs));
566 // _pp('mktime: '.date('r',mktime()));
567 // _pp('timeLastRun: '.date('r',$lastRunTs));
573 foreach($hrName as $kHr=>$hr) {
574 foreach($minName as $kMin=>$min) {
575 $timedate->tzUser($dateobj);
576 $dateobj->setTime($hr, $min, 0);
577 $tsGmt = $dateobj->ts;
579 if( $tsGmt >= $timeStartTs ) { // start is greater than the date specified by admin
580 if( $tsGmt >= $timeFromTs ) { // start is greater than the time_to spec'd by admin
581 if($tsGmt > $lastRunTs) { // start from last run, last run should not be included
582 if( $tsGmt <= $timeEndTs ) { // this is taken care of by the initial query - start is less than the date spec'd by admin
583 if( $tsGmt <= $timeToTs ) { // start is less than the time_to
584 $validJobTime[] = $dateobj->asDb();
586 //_pp('Job Time is NOT smaller that TimeTO: '.$tsGmt .'<='. $timeToTs);
589 //_pp('Job Time is NOT smaller that DateTimeEnd: '.date('Y-m-d H:i:s',$tsGmt) .'<='. $dateTimeEnd); //_pp( $tsGmt .'<='. $timeEndTs );
593 //_pp('Job Time is NOT bigger that TimeFrom: '.$tsGmt .'>='. $timeFromTs);
596 //_pp('Job Time is NOT Bigger than DateTimeStart: '.date('Y-m-d H:i',$tsGmt) .'>='. $dateTimeStart);
600 //_ppd($validJobTime);
601 // need ascending order to compare oldest time to last_run
604 * If "Execute If Missed bit is set
606 $now = TimeDate::getInstance()->getNow();
607 $now = $now->setTime($now->hour, $now->min, "00")->asDb();
609 if($focus->catch_up == 1) {
610 if($focus->last_run == null) {
612 $validJobTime[] = $now;
614 // determine what the interval in min/hours is
615 // see if last_run is in it
617 if(!empty($validJobTime) && ($focus->last_run < $validJobTime[0]) && ($now > $validJobTime[0])) {
618 // cn: empty() bug 5914;
619 //if(!empty) should be checked, becasue if a scheduler is defined to run every day 4pm, then after 4pm, and it runs as 4pm, the $validJobTime will be empty, and it should not catch up
620 //if $focus->last_run is the the day before yesterday, it should run yesterday and tomorrow, but it hadn't run yesterday, then it should catch up today. But today is already filtered out when doing date check before. The catch up will not work on this occasion. If the scheduler runs at least one time on each day, I think this bug can be avoided.
621 $validJobTime[] = $now;
625 return $validJobTime;
628 function handleIntervalType($type, $value, $mins, $hours) {
630 /* [0]:min [1]:hour [2]:day of month [3]:month [4]:day of week */
631 $days = array ( 0 => $mod_strings['LBL_MON'],
632 1 => $mod_strings['LBL_TUE'],
633 2 => $mod_strings['LBL_WED'],
634 3 => $mod_strings['LBL_THU'],
635 4 => $mod_strings['LBL_FRI'],
636 5 => $mod_strings['LBL_SAT'],
637 6 => $mod_strings['LBL_SUN'],
638 '*' => $mod_strings['LBL_ALL']);
643 return trim($mod_strings['LBL_ON_THE']).$mod_strings['LBL_HOUR_SING'];
644 } elseif(!preg_match('/[^0-9]/', $hours) && !preg_match('/[^0-9]/', $value)) {
647 } elseif(preg_match('/\*\//', $value)) {
648 $value = str_replace('*/','',$value);
649 return $value.$mod_strings['LBL_MINUTES'];
650 } elseif(!preg_match('[^0-9]', $value)) {
651 return $mod_strings['LBL_ON_THE'].$value.$mod_strings['LBL_MIN_MARK'];
656 global $current_user;
657 if(preg_match('/\*\//', $value)) { // every [SOME INTERVAL] hours
658 $value = str_replace('*/','',$value);
659 return $value.$mod_strings['LBL_HOUR'];
660 } elseif(preg_match('/[^0-9]/', $mins)) { // got a range, or multiple of mins, so we return an 'Hours' label
662 } else { // got a "minutes" setting, so it will be at some o'clock.
663 $datef = $current_user->getUserDateTimePreferences();
664 return date($datef['time'], strtotime($value.':'.str_pad($mins, 2, '0', STR_PAD_LEFT)));
666 case 2: // day of month
667 if(preg_match('/\*/', $value)) {
670 return date('jS', strtotime('December '.$value));
674 return date('F', strtotime('2005-'.$value.'-01'));
675 case 4: // days of week
676 return $days[$value];
678 return 'bad'; // no condition to touch this branch
682 function setIntervalHumanReadable() {
683 global $current_user;
686 /* [0]:min [1]:hour [2]:day of month [3]:month [4]:day of week */
687 $ints = $this->intervalParsed;
688 $intVal = array('-', ',');
689 $intSub = array($mod_strings['LBL_RANGE'], $mod_strings['LBL_AND']);
690 $intInt = array(0 => $mod_strings['LBL_MINS'], 1 => $mod_strings['LBL_HOUR']);
694 foreach($ints['raw'] as $key => $interval) {
695 if($tempInt != $iteration) {
698 $iteration = $tempInt;
700 if($interval != '*' && $interval != '*/1') {
701 if(false !== strpos($interval, ',')) {
702 $exIndiv = explode(',', $interval);
703 foreach($exIndiv as $val) {
704 if(false !== strpos($val, '-')) {
705 $exRange = explode('-', $val);
706 foreach($exRange as $valRange) {
708 $tempInt .= $mod_strings['LBL_AND'];
710 $tempInt .= $this->handleIntervalType($key, $valRange, $ints['raw'][0], $ints['raw'][1]);
712 } elseif($tempInt != $iteration) {
713 $tempInt .= $mod_strings['LBL_AND'];
715 $tempInt .= $this->handleIntervalType($key, $val, $ints['raw'][0], $ints['raw'][1]);
717 } elseif(false !== strpos($interval, '-')) {
718 $exRange = explode('-', $interval);
719 $tempInt .= $mod_strings['LBL_FROM'];
722 foreach($exRange as $val) {
723 if($tempInt == $check) {
724 $tempInt .= $this->handleIntervalType($key, $val, $ints['raw'][0], $ints['raw'][1]);
725 $tempInt .= $mod_strings['LBL_RANGE'];
728 $tempInt .= $this->handleIntervalType($key, $val, $ints['raw'][0], $ints['raw'][1]);
732 } elseif(false !== strpos($interval, '*/')) {
733 $tempInt .= $mod_strings['LBL_EVERY'];
734 $tempInt .= $this->handleIntervalType($key, $interval, $ints['raw'][0], $ints['raw'][1]);
736 $tempInt .= $this->handleIntervalType($key, $interval, $ints['raw'][0], $ints['raw'][1]);
742 $this->intervalHumanReadable = $mod_strings['LBL_OFTEN'];
744 $tempInt = trim($tempInt);
745 if(';' == substr($tempInt, (strlen($tempInt)-1), strlen($tempInt))) {
746 $tempInt = substr($tempInt, 0, (strlen($tempInt)-1));
748 $this->intervalHumanReadable = $tempInt;
753 /* take an integer and return its suffix */
754 function setStandardArraysAttributes() {
756 global $app_list_strings; // using from month _dom list
758 $suffArr = array('','st','nd','rd');
759 for($i=1; $i<32; $i++) {
760 if($i > 3 && $i < 21) {
761 $this->suffixArray[$i] = $i."th";
762 } elseif (substr($i,-1,1) < 4 && substr($i,-1,1) > 0) {
763 $this->suffixArray[$i] = $i.$suffArr[substr($i,-1,1)];
765 $this->suffixArray[$i] = $i."th";
767 $this->datesArray[$i] = $i;
770 $this->dayInt = array('*',1,2,3,4,5,6,7);
771 $this->dayLabel = array('*',$mod_strings['LBL_MON'],$mod_strings['LBL_TUE'],$mod_strings['LBL_WED'],$mod_strings['LBL_THU'],$mod_strings['LBL_FRI'],$mod_strings['LBL_SAT'],$mod_strings['LBL_SUN']);
772 $this->monthsInt = array(0,1,2,3,4,5,6,7,8,9,10,11,12);
773 $this->monthsLabel = $app_list_strings['dom_cal_month_long'];
774 $this->metricsVar = array("*", "/", "-", ",");
775 $this->metricsVal = array(' every ','',' thru ',' and ');
779 * takes the serialized interval string and renders it into an array
781 function parseInterval() {
783 $ws = array(' ', '\r','\t');
784 $blanks = array('','','');
786 $intv = $this->job_interval;
787 $rawValues = explode('::', $intv);
788 $rawProcessed = str_replace($ws,$blanks,$rawValues); // strip all whitespace
790 $hours = $rawValues[1].':::'.$rawValues[0];
791 $months = $rawValues[3].':::'.$rawValues[2];
793 $intA = array ( 'raw' => $rawProcessed,
798 $this->intervalParsed = $intA;
802 * soft-deletes all job logs older than 24 hours
804 function cleanJobLog()
806 $GLOBALS['log']->info('DELETE FROM schedulers_times WHERE date_entered < '.db_convert("'" . TimeDate::getInstance()->getNow()->get("-1 day")->asDb() . "'", 'datetime'));
807 $this->db->query('DELETE FROM schedulers_times WHERE date_entered < '.db_convert("'" . TimeDate::getInstance()->getNow()->get("-1 day")->asDb() . "'", 'datetime'));
811 * checks for cURL libraries
813 function checkCurl() {
816 if(!function_exists('curl_init')) {
818 <table cellpadding="0" cellspacing="0" width="100%" border="0" class="list view">
820 <th width="25%" colspan="2"><slot>
821 '.$mod_strings['LBL_WARN_CURL_TITLE'].'
824 <tr class="oddListRowS1" >
825 <td scope="row" valign=TOP width="20%"><slot>
826 '.$mod_strings['LBL_WARN_CURL'].'
827 <td scope="row" valign=TOP width="80%"><slot>
828 <span class=error>'.$mod_strings['LBL_WARN_NO_CURL'].'</span>
836 function displayCronInstructions() {
838 global $sugar_config;
840 if (!isset($_SERVER['Path'])) {
841 $_SERVER['Path'] = getenv('Path');
844 if(isset($_SERVER['Path']) && !empty($_SERVER['Path'])) { // IIS IUSR_xxx may not have access to Path or it is not set
845 if(!strpos($_SERVER['Path'], 'php')) {
846 // $error = '<em>'.$mod_strings['LBL_NO_PHP_CLI'].'</em>';
850 if(isset($_SERVER['Path']) && !empty($_SERVER['Path'])) { // some Linux servers do not make this available
851 if(!strpos($_SERVER['PATH'], 'php')) {
852 // $error = '<em>'.$mod_strings['LBL_NO_PHP_CLI'].'</em>';
862 <table cellpadding="0" cellspacing="0" width="100%" border="0" class="list view">
865 '.$mod_strings['LBL_CRON_INSTRUCTIONS_WINDOWS'].'
868 <tr class="evenListRowS1">
869 <td scope="row" valign="top" width="70%"><slot>
870 '.$mod_strings['LBL_CRON_WINDOWS_DESC'].'<br>
871 <b>cd '.realpath('./').'<br>
872 php.exe -f cron.php</b>
879 <table cellpadding="0" cellspacing="0" width="100%" border="0" class="list view">
882 '.$mod_strings['LBL_CRON_INSTRUCTIONS_LINUX'].'
886 <td scope="row" valign=TOP class="oddListRowS1" bgcolor="#fdfdfd" width="70%"><slot>
887 '.$mod_strings['LBL_CRON_LINUX_DESC'].'<br>
888 <b>* * * * *
889 cd '.realpath('./').'; php -f cron.php > /dev/null 2>&1</b>
898 * Archives schedulers of the same functionality, then instantiates new
901 function rebuildDefaultSchedulers() {
903 // truncate scheduler-related tables
904 $this->db->query('DELETE FROM schedulers');
905 $this->db->query('DELETE FROM schedulers_times');
908 $sched3 = new Scheduler();
909 $sched3->name = $mod_strings['LBL_OOTB_TRACKER'];
910 $sched3->job = 'function::trimTracker';
911 $sched3->date_time_start = create_date(2005,1,1) . ' ' . create_time(0,0,1);
912 $sched3->date_time_end = create_date(2020,12,31) . ' ' . create_time(23,59,59);
913 $sched3->job_interval = '0::2::1::*::*';
914 $sched3->status = 'Active';
915 $sched3->created_by = '1';
916 $sched3->modified_user_id = '1';
917 $sched3->catch_up = '1';
919 $sched4 = new Scheduler();
920 $sched4->name = $mod_strings['LBL_OOTB_IE'];
921 $sched4->job = 'function::pollMonitoredInboxes';
922 $sched4->date_time_start = create_date(2005,1,1) . ' ' . create_time(0,0,1);
923 $sched4->date_time_end = create_date(2020,12,31) . ' ' . create_time(23,59,59);
924 $sched4->job_interval = '*::*::*::*::*';
925 $sched4->status = 'Active';
926 $sched4->created_by = '1';
927 $sched4->modified_user_id = '1';
928 $sched4->catch_up = '0';
931 $sched5 = new Scheduler();
932 $sched5->name = $mod_strings['LBL_OOTB_BOUNCE'];
933 $sched5->job = 'function::pollMonitoredInboxesForBouncedCampaignEmails';
934 $sched5->date_time_start = create_date(2005,1,1) . ' ' . create_time(0,0,1);
935 $sched5->date_time_end = create_date(2020,12,31) . ' ' . create_time(23,59,59);
936 $sched5->job_interval = '0::2-6::*::*::*';
937 $sched5->status = 'Active';
938 $sched5->created_by = '1';
939 $sched5->modified_user_id = '1';
940 $sched5->catch_up = '1';
943 $sched6 = new Scheduler();
944 $sched6->name = $mod_strings['LBL_OOTB_CAMPAIGN'];
945 $sched6->job = 'function::runMassEmailCampaign';
946 $sched6->date_time_start = create_date(2005,1,1) . ' ' . create_time(0,0,1);
947 $sched6->date_time_end = create_date(2020,12,31) . ' ' . create_time(23,59,59);
948 $sched6->job_interval = '0::2-6::*::*::*';
949 $sched6->status = 'Active';
950 $sched6->created_by = '1';
951 $sched6->modified_user_id = '1';
952 $sched6->catch_up = '1';
956 $sched7 = new Scheduler();
957 $sched7->name = $mod_strings['LBL_OOTB_PRUNE'];
958 $sched7->job = 'function::pruneDatabase';
959 $sched7->date_time_start = create_date(2005,1,1) . ' ' . create_time(0,0,1);
960 $sched7->date_time_end = create_date(2020,12,31) . ' ' . create_time(23,59,59);
961 $sched7->job_interval = '0::4::1::*::*';
962 $sched7->status = 'Inactive';
963 $sched7->created_by = '1';
964 $sched7->modified_user_id = '1';
965 $sched7->catch_up = '0';
974 //// END SCHEDULER HELPER FUNCTIONS
975 ///////////////////////////////////////////////////////////////////////////
978 ///////////////////////////////////////////////////////////////////////////
979 //// STANDARD SUGARBEAN OVERRIDES
981 * function overrides the one in SugarBean.php
983 function create_export_query($order_by, $where, $show_deleted = 0) {
984 return $this->create_new_list_query($order_by, $where,array(),array(), $show_deleted = 0);
988 * function overrides the one in SugarBean.php
992 * function overrides the one in SugarBean.php
994 function fill_in_additional_list_fields() {
995 $this->fill_in_additional_detail_fields();
999 * function overrides the one in SugarBean.php
1001 function fill_in_additional_detail_fields() {
1005 * function overrides the one in SugarBean.php
1007 function get_list_view_data(){
1008 global $mod_strings;
1009 $temp_array = $this->get_list_view_array();
1010 $temp_array["ENCODED_NAME"]=$this->name;
1011 $this->parseInterval();
1012 $this->setIntervalHumanReadable();
1013 $temp_array['JOB_INTERVAL'] = $this->intervalHumanReadable;
1014 if($this->date_time_end == '2020-12-31 23:59' || $this->date_time_end == '') {
1015 $temp_array['DATE_TIME_END'] = $mod_strings['LBL_PERENNIAL'];
1017 $this->created_by_name = get_assigned_user_name($this->created_by);
1018 $this->modified_by_name = get_assigned_user_name($this->modified_user_id);
1024 * returns the bean name - overrides SugarBean's
1026 function get_summary_text() {
1029 //// END STANDARD SUGARBEAN OVERRIDES
1030 ///////////////////////////////////////////////////////////////////////////
1031 } // end class definition