diff --git a/admin/index.php b/admin/index.php
index e045b580..ec257857 100644
--- a/admin/index.php
+++ b/admin/index.php
@@ -87,7 +87,8 @@ print "
" . T_("System settings") . "
";
print "";
+print "" . T_("Set centre information") . "";
+print "" . T_("Start and monitor system wide case sorting") . "";
if (VOIP_ENABLED)
{
diff --git a/admin/systemsort.php b/admin/systemsort.php
new file mode 100644
index 00000000..64410481
--- /dev/null
+++ b/admin/systemsort.php
@@ -0,0 +1,100 @@
+
+/**
+ * Run the system wide case sorting process and monitor it's progress
+ *
+ *
+ * This file is part of queXS
+ *
+ * queXS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * queXS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with queXS; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *
+ * @author Adam Zammit
+ * @copyright Australian Consortium for Social and Political Research Incorporated (ACSPRI) 2011
+ * @package queXS
+ * @subpackage admin
+ * @link http://www.acspri.org.au/ queXS was writen for ACSPRI
+ * @license http://opensource.org/licenses/gpl-2.0.php The GNU General Public License (GPL) Version 2
+ *
+ */
+
+/**
+ * Configuration file
+ */
+include ("../config.inc.php");
+
+/**
+ * Database file
+ */
+include ("../db.inc.php");
+
+/**
+ * Process
+ */
+include ("../functions/functions.process.php");
+
+/**
+ * XHTML functions
+ */
+include("../functions/functions.xhtml.php");
+
+
+
+if (isset($_GET['watch']))
+{
+ //start watching process
+ start_process(realpath(dirname(__FILE__) . "/systemsortprocess.php"),2);
+}
+
+$p = is_process_running(2);
+
+
+if ($p)
+{
+ if (isset($_GET['kill']))
+ {
+ if ($_GET['kill'] == "force")
+ end_process($p);
+ else
+ kill_process($p);
+ }
+
+ xhtml_head(T_("Monitor system wide case sorting"),true,false,false,false,false,true);
+
+ print "" . T_("Running process:") . " $p
";
+
+ if (is_process_killed($p))
+ {
+ print "" . T_("Kill signal sent: Please wait...") . "
";
+ print "" . T_("Process is already closed (eg. server was rebooted) - click here to confirm") . "
";
+ }
+ else
+ {
+ print "" . T_("Kill the running process") . "
";
+ }
+
+ print process_get_data($p);
+}
+else
+{
+ xhtml_head(T_("Monitor system wide case sorting"));
+ print "" . T_("Monitor system wide case sorting") . "
";
+ print "" . T_("Click here to enable and begin system wide case sorting") . "
";
+ print "" . T_("System wide case sorting is periodically (via SYSTEM_SORT_MINUTES configuration directive) sorting cases on a system wide basis instead of finding the most appropriate case each time an operator requests a new case. This may increase performance where there are a large number of cases or complex quotas in place. If you are not experiencing any performance problems, it is not recommended to use this feature.") . "
";
+ print "" . T_("Outcome of last process run (if any)") . "
";
+ print process_get_last_data(2);
+}
+xhtml_foot();
+
+?>
diff --git a/admin/systemsortprocess.php b/admin/systemsortprocess.php
new file mode 100644
index 00000000..53add884
--- /dev/null
+++ b/admin/systemsortprocess.php
@@ -0,0 +1,194 @@
+
+/**
+ * Run the system wide case sorting process
+ *
+ *
+ * This file is part of queXS
+ *
+ * queXS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * queXS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with queXS; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *
+ * @author Adam Zammit
+ * @copyright Australian Consortium for Social and Political Research Incorporated (ACSPRI) 2011
+ * @package queXS
+ * @subpackage admin
+ * @link http://www.acspri.org.au/ queXS was written for ACSPRI
+ * @license http://opensource.org/licenses/gpl-2.0.php The GNU General Public License (GPL) Version 2
+ *
+ */
+
+/**
+ * Configuration file
+ */
+include (dirname(__FILE__) . "/../config.inc.php");
+
+/**
+ * Database file
+ */
+include (dirname(__FILE__) . "/../db.inc.php");
+
+/**
+ * Process
+ */
+include (dirname(__FILE__) . "/../functions/functions.process.php");
+
+/**
+ * Update the database with the new data from the running script
+ *
+ * @param string $buffer The data to append to the database
+ * @return string Return a blank string to empty the buffer
+ */
+function update_callback($buffer)
+{
+ global $process_id;
+
+ process_append_data($process_id,"" . $buffer . "
");
+
+ return ""; //empty buffer
+}
+
+/**
+ * Disable system sort on shutdown
+ *
+ * @author Adam Zammit
+ * @since 2011-01-31
+ */
+function disable_systemsort()
+{
+ set_setting('systemsort',false);
+}
+
+
+//get the arguments from the command line (this process_id)
+if ($argc != 2) exit();
+
+$process_id = $argv[1];
+
+//register an exit function which will tell the database we have ended
+register_shutdown_function('end_process',$process_id);
+register_shutdown_function('disable_systemsort');
+
+//all output send to database instead of stdout
+ob_start('update_callback',2);
+
+print T_("Sorting cases process starting");
+
+$sleepinterval = 10; // in seconds so we can monitor if the process has been killed
+
+while (!is_process_killed($process_id)) //check if process killed every $sleepinterval
+{
+ //Make sure that the system knows we are system sorting
+ set_setting('systemsort',true);
+
+ print date("Y-m-d H:i") . " : " . T_("Sorting cases");
+
+ $time_start = microtime(true);
+
+ $db->StartTrans();
+
+ //Sort current cases for all enabled questionnaires
+
+
+ $sql = "SELECT c.case_id
+ FROM `case` as c
+ LEFT JOIN `call` as a on (a.call_id = c.last_call_id)
+ JOIN (sample as s, sample_import as si) on (s.sample_id = c.sample_id and si.sample_import_id = s.import_id)
+ JOIN (questionnaire_sample as qs, questionnaire as q, outcome as ou) on (c.questionnaire_id = q.questionnaire_id and qs.sample_import_id = s.import_id and ou.outcome_id = c.current_outcome_id and q.enabled = 1)
+ LEFT JOIN shift as sh on (sh.questionnaire_id = q.questionnaire_id and (CONVERT_TZ(NOW(),'System','UTC') >= sh.start) AND (CONVERT_TZ(NOW(),'System','UTC') <= sh.end))
+ LEFT JOIN appointment as ap on (ap.case_id = c.case_id AND ap.completed_call_id is NULL AND (ap.start > CONVERT_TZ(NOW(),'System','UTC')))
+ LEFT JOIN appointment as apn on (apn.case_id = c.case_id AND apn.completed_call_id is NULL AND (CONVERT_TZ(NOW(),'System','UTC') >= apn.start) AND (CONVERT_TZ(NOW(),'System','UTC') <= apn.end))
+ LEFT JOIN call_restrict as cr on (cr.day_of_week = DAYOFWEEK(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) and TIME(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) >= cr.start and TIME(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) <= cr.end)
+ LEFT JOIN questionnaire_sample_exclude_priority AS qsep ON (qsep.questionnaire_id = c.questionnaire_id AND qsep.sample_id = c.sample_id)
+ WHERE c.current_operator_id IS NULL
+ AND (a.call_id is NULL or (a.end < CONVERT_TZ(DATE_SUB(NOW(), INTERVAL ou.default_delay_minutes MINUTE),'System','UTC')))
+ AND ap.case_id is NULL
+ AND ((qsep.questionnaire_id is NULL) or qsep.exclude = 0)
+ AND !(q.restrict_work_shifts = 1 AND sh.shift_id IS NULL)
+ AND !(si.call_restrict = 1 AND cr.day_of_week IS NULL)
+ AND ((apn.appointment_id IS NOT NULL) or qs.call_attempt_max = 0 or ((SELECT count(*) FROM call_attempt WHERE case_id = c.case_id) < qs.call_attempt_max))
+ AND ((apn.appointment_id IS NOT NULL) or qs.call_max = 0 or ((SELECT count(*) FROM `call` WHERE case_id = c.case_id) < qs.call_max))
+ AND (SELECT count(*) FROM `questionnaire_sample_quota` WHERE questionnaire_id = c.questionnaire_id AND sample_import_id = s.import_id AND quota_reached = 1) = 0
+ GROUP BY c.case_id
+ ORDER BY apn.start DESC, a.start ASC, qsep.priority DESC";
+
+ $rs = $db->GetAll($sql);
+
+ $i = 1;
+ foreach ($rs as $r)
+ {
+ $sql = "UPDATE `case`
+ SET sortorder = '$i'
+ WHERE case_id = '{$r['case_id']}'";
+
+ $db->Execute($sql);
+ $i++;
+ }
+
+ //Sort sample list where attached to an enabled questionnaire
+
+ $sql = "SELECT s.sample_id as sample_id,qs.questionnaire_id as questionnaire_id
+ FROM sample as s
+ JOIN (questionnaire_sample as qs, questionnaire as q, sample_import as si) on (qs.sample_import_id = s.import_id and si.sample_import_id = s.import_id and q.questionnaire_id = qs.questionnaire_id AND q.enabled = 1)
+ LEFT JOIN `case` as c on (c.sample_id = s.sample_id and c.questionnaire_id = qs.questionnaire_id)
+ LEFT JOIN call_restrict as cr on (cr.day_of_week = DAYOFWEEK(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) and TIME(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) >= cr.start and TIME(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) <= cr.end)
+ LEFT JOIN shift as sh on (sh.questionnaire_id = q.questionnaire_id and (CONVERT_TZ(NOW(),'System','UTC') >= sh.start) AND (CONVERT_TZ(NOW(),'System','UTC') <= sh.end))
+ LEFT JOIN questionnaire_sample_exclude_priority AS qsep ON (qsep.questionnaire_id = qs.questionnaire_id AND qsep.sample_id = s.sample_id)
+ WHERE c.case_id is NULL
+ AND ((qsep.questionnaire_id IS NULL) or qsep.exclude = 0)
+ AND !(q.restrict_work_shifts = 1 AND sh.shift_id IS NULL)
+ AND !(si.call_restrict = 1 AND cr.day_of_week IS NULL)
+ AND (SELECT count(*) FROM `questionnaire_sample_quota` WHERE questionnaire_id = qs.questionnaire_id AND sample_import_id = s.import_id AND quota_reached = 1) = 0
+ GROUP BY s.sample_id,qs.questionnaire_id
+ ORDER BY qsep.priority DESC, rand() * qs.random_select, s.sample_id";
+
+ $rs = $db->GetAll($sql);
+
+ $i = 1;
+ foreach ($rs as $r)
+ {
+ $sql = "INSERT INTO questionnaire_sample_exclude_priority (questionnaire_id,sample_id,exclude,priority,sortorder)
+ VALUES ('{$r['questionnaire_id']}', '{$r['sample_id']}', 0, 50,'$i')
+ ON DUPLICATE KEY UPDATE sortorder = '$i'";
+
+ $db->Execute($sql);
+ $i++;
+ }
+
+
+
+
+ $result = $db->CompleteTrans();
+
+ $time_end = microtime(true);
+ $timer = $time_end - $time_start;
+
+ if ($result)
+ print T_("Completed sort") . ". " . T_("This task took") . ": $timer " . T_("seconds");
+ else
+ print T_("Failed to complete sort") . ". " . T_("This task took") . ": $timer " . T_("seconds");
+
+ for ($i = 0; $i < (SYSTEM_SORT_MINUTES * 60); $i += $sleepinterval)
+ {
+ if (is_process_killed($process_id)){break;}
+ sleep($sleepinterval);
+ }
+}
+
+disable_systemsort();
+
+ob_get_contents();
+ob_end_clean();
+
+?>
diff --git a/config.default.php b/config.default.php
index 146d5573..ae54c5c4 100644
--- a/config.default.php
+++ b/config.default.php
@@ -220,6 +220,11 @@ if (!defined('TAB_INFO')) define('TAB_INFO', true);
*/
if (!defined('HEADER_EXPANDER')) define('HEADER_EXPANDER', false);
+/**
+ * Define how many minutes between each system sort (defaults to 5 as this is a common interval for appointments)
+ */
+if (!defined('SYSTEM_SORT_MINUTES')) define ('SYSTEM_SORT_MINUTES',5);
+
/**
* Database configuration for queXS
*/
diff --git a/database/quexs.sql b/database/quexs.sql
index dfa05914..2a9e6c02 100644
--- a/database/quexs.sql
+++ b/database/quexs.sql
@@ -176,12 +176,14 @@ CREATE TABLE `case` (
`current_operator_id` bigint(20) default NULL,
`current_call_id` bigint(20) default NULL,
`current_outcome_id` int(11) NOT NULL default '1',
+ `sortorder` int(11) default NULL,
PRIMARY KEY (`case_id`),
UNIQUE KEY `onecasepersample` (`sample_id`,`questionnaire_id`),
UNIQUE KEY `current_operator_id` (`current_operator_id`),
UNIQUE KEY `current_call_id` (`current_call_id`),
KEY `sample_id` (`sample_id`),
- KEY `questionnaire_id` (`questionnaire_id`)
+ KEY `questionnaire_id` (`questionnaire_id`),
+ KEY `sortorder` (`sortorder`)
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
@@ -441,6 +443,7 @@ INSERT INTO `outcome_type` VALUES(5, 'Appointments');
CREATE TABLE `process` (
`process_id` bigint(20) NOT NULL auto_increment,
+ `type` int(11) NOT NULL default '1',
`start` datetime NOT NULL,
`stop` datetime default NULL,
`kill` tinyint(1) NOT NULL default '0',
@@ -522,10 +525,12 @@ CREATE TABLE `questionnaire_sample_exclude_priority` (
`sample_id` bigint(20) NOT NULL,
`exclude` tinyint(1) NOT NULL default '0',
`priority` tinyint(3) NOT NULL default '50',
+ `sortorder` int(11) default NULL,
PRIMARY KEY (`questionnaire_id`,`sample_id`),
KEY `exclude` (`exclude`),
KEY `priority` (`priority`),
- KEY `questionnaire_id` (`questionnaire_id`)
+ KEY `questionnaire_id` (`questionnaire_id`),
+ KEY `sortorder` (`sortorder`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
--
diff --git a/functions/functions.operator.php b/functions/functions.operator.php
index 1d52a0f0..019443af 100644
--- a/functions/functions.operator.php
+++ b/functions/functions.operator.php
@@ -295,86 +295,122 @@ function get_case_id($operator_id, $create = false)
{
if ($create)
{
- /**
- * find a case that:
- * Has not been called in the last x hours based on last outcome
- * Is available for this operator
- * Has no appointments scheduled in the future (can also check if outcome is appointment)
- * Nobody else is servicing the call at the moment
- * The case is not referred to the supervisor and the operator is not the supervisor
- * The case is not on a refusal outcome and the operator is not a refusal converter
- * Give priority if there is an appointment scheduled now
- * If restricted to shift times to work, make sure we are in those
- * If restricted to respondent call times, make sure we are in those
- * Only assign if outcome type is assigned to the operator
- * Has not reached the quota
- *
- *
- * THINGS TO ADD:
- *
- * @todo also option of "time of day" calls - try once in the morning/etc
- * @todo also could check the respondent_not_available table to see if now is a "bad time" to call
- */
+ $systemsort = get_setting('systemsort');
+
+ if ($systemsort)
+ {
+ //Just make sure that this case should go to this operator (assigned to this project and skill)
+ $sql = "SELECT c.case_id as caseid
+ FROM `case` as c
+ JOIN operator_questionnaire AS oq ON (oq.operator_id = '$operator_id' AND oq.questionnaire_id = c.questionnaire_id)
+ JOIN outcome as ou ON (ou.outcome_id = c.current_outcome_id)
+ JOIN operator_skill as os ON (os.operator_id = '$operator_id' AND os.outcome_type_id = ou.outcome_type_id)
+ WHERE c.sortorder IS NOT NULL
+ AND c.current_operator_id IS NULL
+ ORDER BY c.sortorder ASC
+ LIMIT 1";
+
+ }
+ else
+ {
+ /**
+ * find a case that:
+ * Has not been called in the last x hours based on last outcome
+ * Is available for this operator
+ * Has no appointments scheduled in the future (can also check if outcome is appointment)
+ * Nobody else is servicing the call at the moment
+ * The case is not referred to the supervisor and the operator is not the supervisor
+ * The case is not on a refusal outcome and the operator is not a refusal converter
+ * Give priority if there is an appointment scheduled now
+ * If restricted to shift times to work, make sure we are in those
+ * If restricted to respondent call times, make sure we are in those
+ * Only assign if outcome type is assigned to the operator
+ * Has not reached the quota
+ *
+ *
+ * THINGS TO ADD:
+ *
+ * @todo also option of "time of day" calls - try once in the morning/etc
+ * @todo also could check the respondent_not_available table to see if now is a "bad time" to call
+ */
+
+ $sql = "SELECT c.case_id as caseid,s.*,apn.*,a.*,sh.*,op.*,cr.*,si.*,CONVERT_TZ(NOW(), 'System' , s.Time_zone_name) as resptime
+ FROM `case` as c
+ LEFT JOIN `call` as a on (a.call_id = c.last_call_id)
+ JOIN (sample as s, sample_import as si) on (s.sample_id = c.sample_id and si.sample_import_id = s.import_id)
+ JOIN (questionnaire_sample as qs, operator_questionnaire as o, questionnaire as q, operator as op, outcome as ou) on (c.questionnaire_id = q.questionnaire_id and op.operator_id = '$operator_id' and qs.sample_import_id = s.import_id and o.operator_id = op.operator_id and o.questionnaire_id = qs.questionnaire_id and q.questionnaire_id = o.questionnaire_id and ou.outcome_id = c.current_outcome_id)
+ LEFT JOIN shift as sh on (sh.questionnaire_id = q.questionnaire_id and (CONVERT_TZ(NOW(),'System','UTC') >= sh.start) AND (CONVERT_TZ(NOW(),'System','UTC') <= sh.end))
+ LEFT JOIN appointment as ap on (ap.case_id = c.case_id AND ap.completed_call_id is NULL AND (ap.start > CONVERT_TZ(NOW(),'System','UTC')))
+ LEFT JOIN appointment as apn on (apn.case_id = c.case_id AND apn.completed_call_id is NULL AND (CONVERT_TZ(NOW(),'System','UTC') >= apn.start) AND (CONVERT_TZ(NOW(),'System','UTC') <= apn.end))
+ LEFT JOIN call_restrict as cr on (cr.day_of_week = DAYOFWEEK(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) and TIME(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) >= cr.start and TIME(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) <= cr.end)
+ LEFT JOIN questionnaire_sample_exclude_priority AS qsep ON (qsep.questionnaire_id = c.questionnaire_id AND qsep.sample_id = c.sample_id)
+ JOIN operator_skill as os on (os.operator_id = op.operator_id and os.outcome_type_id = ou.outcome_type_id)
+ WHERE c.current_operator_id IS NULL
+ AND (a.call_id is NULL or (a.end < CONVERT_TZ(DATE_SUB(NOW(), INTERVAL ou.default_delay_minutes MINUTE),'System','UTC')))
+ AND ap.case_id is NULL
+ AND ((qsep.questionnaire_id is NULL) or qsep.exclude = 0)
+ AND !(q.restrict_work_shifts = 1 AND sh.shift_id IS NULL AND os.outcome_type_id != 2)
+ AND !(si.call_restrict = 1 AND cr.day_of_week IS NULL AND os.outcome_type_id != 2)
+ AND ((apn.appointment_id IS NOT NULL) or qs.call_attempt_max = 0 or ((SELECT count(*) FROM call_attempt WHERE case_id = c.case_id) < qs.call_attempt_max))
+ AND ((apn.appointment_id IS NOT NULL) or qs.call_max = 0 or ((SELECT count(*) FROM `call` WHERE case_id = c.case_id) < qs.call_max))
+ AND (SELECT count(*) FROM `questionnaire_sample_quota` WHERE questionnaire_id = c.questionnaire_id AND sample_import_id = s.import_id AND quota_reached = 1) = 0
+ ORDER BY apn.start DESC, a.start ASC, qsep.priority DESC
+ LIMIT 1";
- $sql = "SELECT c.case_id as caseid,s.*,apn.*,a.*,sh.*,op.*,cr.*,si.*,CONVERT_TZ(NOW(), 'System' , s.Time_zone_name) as resptime
- FROM `case` as c
- LEFT JOIN `call` as a on (a.call_id = c.last_call_id)
- JOIN (sample as s, sample_import as si) on (s.sample_id = c.sample_id and si.sample_import_id = s.import_id)
- JOIN (questionnaire_sample as qs, operator_questionnaire as o, questionnaire as q, operator as op, outcome as ou) on (c.questionnaire_id = q.questionnaire_id and op.operator_id = '$operator_id' and qs.sample_import_id = s.import_id and o.operator_id = op.operator_id and o.questionnaire_id = qs.questionnaire_id and q.questionnaire_id = o.questionnaire_id and ou.outcome_id = c.current_outcome_id)
- LEFT JOIN shift as sh on (sh.questionnaire_id = q.questionnaire_id and (CONVERT_TZ(NOW(),'System','UTC') >= sh.start) AND (CONVERT_TZ(NOW(),'System','UTC') <= sh.end))
- LEFT JOIN appointment as ap on (ap.case_id = c.case_id AND ap.completed_call_id is NULL AND (ap.start > CONVERT_TZ(NOW(),'System','UTC')))
- LEFT JOIN appointment as apn on (apn.case_id = c.case_id AND apn.completed_call_id is NULL AND (CONVERT_TZ(NOW(),'System','UTC') >= apn.start) AND (CONVERT_TZ(NOW(),'System','UTC') <= apn.end))
- LEFT JOIN call_restrict as cr on (cr.day_of_week = DAYOFWEEK(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) and TIME(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) >= cr.start and TIME(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) <= cr.end)
- LEFT JOIN questionnaire_sample_exclude_priority AS qsep ON (qsep.questionnaire_id = c.questionnaire_id AND qsep.sample_id = c.sample_id)
- JOIN operator_skill as os on (os.operator_id = op.operator_id and os.outcome_type_id = ou.outcome_type_id)
- WHERE c.current_operator_id IS NULL
- AND (a.call_id is NULL or (a.end < CONVERT_TZ(DATE_SUB(NOW(), INTERVAL ou.default_delay_minutes MINUTE),'System','UTC')))
- AND ap.case_id is NULL
- AND ((qsep.questionnaire_id is NULL) or qsep.exclude = 0)
- AND !(q.restrict_work_shifts = 1 AND sh.shift_id IS NULL AND os.outcome_type_id != 2)
- AND !(si.call_restrict = 1 AND cr.day_of_week IS NULL AND os.outcome_type_id != 2)
- AND ((apn.appointment_id IS NOT NULL) or qs.call_attempt_max = 0 or ((SELECT count(*) FROM call_attempt WHERE case_id = c.case_id) < qs.call_attempt_max))
- AND ((apn.appointment_id IS NOT NULL) or qs.call_max = 0 or ((SELECT count(*) FROM `call` WHERE case_id = c.case_id) < qs.call_max))
- AND (SELECT count(*) FROM `questionnaire_sample_quota` WHERE questionnaire_id = c.questionnaire_id AND sample_import_id = s.import_id AND quota_reached = 1) = 0
- ORDER BY apn.start DESC, a.start ASC, qsep.priority DESC
- LIMIT 1";
-
- //apn.appointment_id contains the id of an appointment if we are calling on an appointment
+ //apn.appointment_id contains the id of an appointment if we are calling on an appointment
+ }
$r2 = $db->GetRow($sql);
if (empty($r2))
{
+ if ($systemsort)
+ {
+ //Just make sure that this case should go to this operator (assigned to this project and skill)
+ $sql = "SELECT qsep.sample_id as sample_id, qsep.questionnaire_id as questionnaire_id
+ FROM questionnaire_sample_exclude_priority as qsep
+ JOIN operator_skill as os ON (os.operator_id = '$operator_id' AND os.outcome_type_id = 1)
+ JOIN operator_questionnaire AS oq ON (oq.operator_id = '$operator_id' AND oq.questionnaire_id = qsep.questionnaire_id)
+ LEFT JOIN `case` as c ON (c.sample_id = qsep.sample_id AND c.questionnaire_id = qsep.sample_id)
+ WHERE qsep.sortorder IS NOT NULL
+ AND c.case_id IS NULL
+ ORDER BY qsep.sortorder ASC
+ LIMIT 1";
- /**
- * If no case found, we must draw the next available case from the sample
- * only if no case due to lack of cases to call not out of shift time/etc and
- * only draw cases that are new (Temporary outcome_type_id)
- *
- *
- * Method:
- * next available that has not been assigned
- * if none available - return false? report to operator that no one available to call at currenet settings
- *
- */
-
-
- $sql = "SELECT s.sample_id as sample_id,c.case_id as case_id,qs.questionnaire_id as questionnaire_id,CONVERT_TZ(NOW(), 'System' , s.Time_zone_name) as resptime, q.testing as testing
- FROM sample as s
- JOIN (questionnaire_sample as qs, operator_questionnaire as o, questionnaire as q, operator as op, sample_import as si, operator_skill as os) on (op.operator_id = '$operator_id' and qs.sample_import_id = s.import_id and o.operator_id = op.operator_id and o.questionnaire_id = qs.questionnaire_id and q.questionnaire_id = o.questionnaire_id and si.sample_import_id = s.import_id and os.operator_id = op.operator_id and os.outcome_type_id = 1)
- LEFT JOIN `case` as c on (c.sample_id = s.sample_id and c.questionnaire_id = qs.questionnaire_id)
- LEFT JOIN call_restrict as cr on (cr.day_of_week = DAYOFWEEK(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) and TIME(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) >= cr.start and TIME(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) <= cr.end)
- LEFT JOIN shift as sh on (sh.questionnaire_id = q.questionnaire_id and (CONVERT_TZ(NOW(),'System','UTC') >= sh.start) AND (CONVERT_TZ(NOW(),'System','UTC') <= sh.end))
- LEFT JOIN questionnaire_sample_exclude_priority AS qsep ON (qsep.questionnaire_id = qs.questionnaire_id AND qsep.sample_id = s.sample_id)
+ }
+ else
+ {
- WHERE c.case_id is NULL
- AND ((qsep.questionnaire_id IS NULL) or qsep.exclude = 0)
- AND !(q.restrict_work_shifts = 1 AND sh.shift_id IS NULL)
- AND !(si.call_restrict = 1 AND cr.day_of_week IS NULL)
- AND (SELECT count(*) FROM `questionnaire_sample_quota` WHERE questionnaire_id = qs.questionnaire_id AND sample_import_id = s.import_id AND quota_reached = 1) = 0
- ORDER BY qsep.priority DESC, rand() * qs.random_select, s.sample_id
- LIMIT 1";
-
+ /**
+ * If no case found, we must draw the next available case from the sample
+ * only if no case due to lack of cases to call not out of shift time/etc and
+ * only draw cases that are new (Temporary outcome_type_id) - this makes sure that we are not drawing
+ * a case just because the operator doesn't have access to temporary outcome id's.
+ *
+ *
+ * Method:
+ * next available that has not been assigned
+ * if none available - return false? report to operator that no one available to call at currenet settings
+ *
+ */
+
+
+ $sql = "SELECT s.sample_id as sample_id,c.case_id as case_id,qs.questionnaire_id as questionnaire_id,CONVERT_TZ(NOW(), 'System' , s.Time_zone_name) as resptime, q.testing as testing
+ FROM sample as s
+ JOIN (questionnaire_sample as qs, operator_questionnaire as o, questionnaire as q, operator as op, sample_import as si, operator_skill as os) on (op.operator_id = '$operator_id' and qs.sample_import_id = s.import_id and o.operator_id = op.operator_id and o.questionnaire_id = qs.questionnaire_id and q.questionnaire_id = o.questionnaire_id and si.sample_import_id = s.import_id and os.operator_id = op.operator_id and os.outcome_type_id = 1)
+ LEFT JOIN `case` as c on (c.sample_id = s.sample_id and c.questionnaire_id = qs.questionnaire_id)
+ LEFT JOIN call_restrict as cr on (cr.day_of_week = DAYOFWEEK(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) and TIME(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) >= cr.start and TIME(CONVERT_TZ(NOW(), 'System' , s.Time_zone_name)) <= cr.end)
+ LEFT JOIN shift as sh on (sh.questionnaire_id = q.questionnaire_id and (CONVERT_TZ(NOW(),'System','UTC') >= sh.start) AND (CONVERT_TZ(NOW(),'System','UTC') <= sh.end))
+ LEFT JOIN questionnaire_sample_exclude_priority AS qsep ON (qsep.questionnaire_id = qs.questionnaire_id AND qsep.sample_id = s.sample_id)
+
+ WHERE c.case_id is NULL
+ AND ((qsep.questionnaire_id IS NULL) or qsep.exclude = 0)
+ AND !(q.restrict_work_shifts = 1 AND sh.shift_id IS NULL)
+ AND !(si.call_restrict = 1 AND cr.day_of_week IS NULL)
+ AND (SELECT count(*) FROM `questionnaire_sample_quota` WHERE questionnaire_id = qs.questionnaire_id AND sample_import_id = s.import_id AND quota_reached = 1) = 0
+ ORDER BY qsep.priority DESC, rand() * qs.random_select, s.sample_id
+ LIMIT 1";
+ }
$r3 = $db->GetRow($sql);
diff --git a/functions/functions.process.php b/functions/functions.process.php
index 6eb2a43b..f74438a1 100644
--- a/functions/functions.process.php
+++ b/functions/functions.process.php
@@ -43,15 +43,17 @@ include_once(dirname(__FILE__).'/../db.inc.php');
/**
* Determine if a process is already running
*
+ * @param int $type Defaults to 1 - specify the process type (class) to search for
* @return bool|int Return false if no process already running, else return the process_id
*/
-function is_process_running()
+function is_process_running($type = 1)
{
global $db;
$sql = "SELECT `process_id`
FROM `process`
- WHERE `stop` IS NULL";
+ WHERE `stop` IS NULL
+ AND type = '$type'";
$rs = $db->GetRow($sql);
@@ -90,23 +92,24 @@ function is_process_killed($process_id)
* Start a process
*
* @param string $filename The PHP file of the process to run
+ * @param int $type The type (class) of process (so we can run multiple processes at the same time) defaults to 1
* @return bool|int False if we couldnt start a process, else the process id from the process table
*
* @link http://www.djkaty.com/php/fork Cross platform process tutorial (this code adapted from here)
*/
-function start_process($filename)
+function start_process($filename,$type = 1)
{
//create a record only if no process already running
global $db;
$db->StartTrans();
- $process = is_process_running();
+ $process = is_process_running($type);
if ($process == false)
{
- $sql = "INSERT INTO `process` (`process_id`,`start`,`stop`,`kill`,`data`)
- VALUES (NULL,CONVERT_TZ(NOW(),'System','UTC'),NULL,0,'')";
+ $sql = "INSERT INTO `process` (`process_id`,`type`,`start`,`stop`,`kill`,`data`)
+ VALUES (NULL,'$type',CONVERT_TZ(NOW(),'System','UTC'),NULL,0,'')";
$rs = $db->Execute($sql);
$args = $db->Insert_ID();
@@ -220,15 +223,17 @@ function process_get_data($process_id)
/**
* Get data from the last process run
*
+ * @param int $type The last processes class (type) defaults to 1
* @return string Data from the last process, or an empty string if not available
*
*/
-function process_get_last_data()
+function process_get_last_data($type = 1)
{
global $db;
$sql = "SELECT `data`
FROM `process`
+ WHERE type = '$type'
ORDER BY `process_id` DESC
LIMIT 1";