diff --git a/admin/index.php b/admin/index.php index 25169a5f..8eff4a55 100644 --- a/admin/index.php +++ b/admin/index.php @@ -54,6 +54,7 @@ print "
  • " . T_("Import a sample file (in CSV form)") . "
  • "; print "
  • " . T_("Assign samples to questionnaires") . "
  • "; print "
  • " . T_("Set values in questionnaire to pre fill") . "
  • "; +print "
  • " . T_("Quota management") . "
  • "; print "
  • " . T_("Add operators to the system") . "
  • "; print "
  • " . T_("Assign operators to questionnaires") . "
  • "; print "
  • " . T_("Modify operator skills") . "
  • "; diff --git a/admin/quota.php b/admin/quota.php new file mode 100755 index 00000000..60fbd773 --- /dev/null +++ b/admin/quota.php @@ -0,0 +1,226 @@ + + * @copyright Deakin University 2007,2008,2009 + * @package queXS + * @subpackage admin + * @link http://www.deakin.edu.au/dcarf/ queXS was writen for DCARF - Deakin Computer Assisted Research Facility + * @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"); + +/** + * XHTML functions + */ +include("../functions/functions.xhtml.php"); + +/** + * Display functions + */ +include("../functions/functions.display.php"); + +/** + * Input functions + */ +include("../functions/functions.input.php"); + +/** + * Limesurvey functions + */ +include("../functions/functions.limesurvey.php"); + +/** + * Operator functions + */ +include("../functions/functions.operator.php"); + + +global $db; + + +if (isset($_GET['questionnaire_id']) && isset($_GET['sgqa']) && isset($_GET['value']) && isset($_GET['completions']) && isset($_GET['sample_import_id']) && isset($_GET['comparison'])) +{ + //need to add quota + + $questionnaire_id = bigintval($_GET['questionnaire_id']); + $sample_import_id = bigintval($_GET['sample_import_id']); + $value = $db->quote($_GET['value']); + $completions = $db->quote($_GET['completions']); + $sgqa = $db->quote($_GET['sgqa']); + $comparison = $db->quote($_GET['comparison']); + + $sql = "INSERT INTO questionnaire_sample_quota(questionnaire_id, sample_import_id, lime_sgqa,value,completions,comparison) + VALUES ($questionnaire_id, $sample_import_id, $sgqa, $value, $completions, $comparison)"; + + $db->Execute($sql); + + //Make sure to calculate on the spot + update_quotas($questionnaire_id); +} + +if (isset($_GET['questionnaire_id']) && isset($_GET['questionnaire_sample_quota_id'])) +{ + //need to remove quota + + $questionnaire_id = bigintval($_GET['questionnaire_id']); + $questionnaire_sample_quota_id = bigintval($_GET['questionnaire_sample_quota_id']); + + $sql = "DELETE FROM questionnaire_sample_quota + WHERE questionnaire_sample_quota_id = '$questionnaire_sample_quota_id'"; + + $db->Execute($sql); + +} + +$questionnaire_id = false; +if (isset($_GET['questionnaire_id'])) $questionnaire_id = bigintval($_GET['questionnaire_id']); + +xhtml_head(T_("Quota management"),true,false,array("../js/window.js")); +print "

    " . T_("Select a questionnaire from the list below") . "

    "; + +$sql = "SELECT questionnaire_id as value,description, CASE WHEN questionnaire_id = '$questionnaire_id' THEN 'selected=\'selected\'' ELSE '' END AS selected + FROM questionnaire"; +display_chooser($db->GetAll($sql),"questionnaire","questionnaire_id"); + + +if ($questionnaire_id != false) +{ + $sample_import_id = false; + if (isset($_GET['sample_import_id'])) $sample_import_id = bigintval($_GET['sample_import_id']); + + print "

    " . T_("Select a sample from the list below") . "

    "; + + $sql = "SELECT s.sample_import_id as value,s.description, CASE WHEN s.sample_import_id = '$sample_import_id' THEN 'selected=\'selected\'' ELSE '' END AS selected + FROM sample_import as s, questionnaire_sample as q + WHERE q.questionnaire_id = $questionnaire_id + AND q.sample_import_id = s.sample_import_id"; + + display_chooser($db->GetAll($sql),"sample","sample_import_id",true,"questionnaire_id=$questionnaire_id"); + + if ($sample_import_id != false) + { + print "

    " . T_("Current quotas (click to delete)") . "

    "; + + $sql = "SELECT questionnaire_sample_quota_id,lime_sgqa,value,completions,quota_reached,lime_sid,comparison + FROM questionnaire_sample_quota as qsq, questionnaire as q + WHERE qsq.questionnaire_id = '$questionnaire_id' + AND qsq.sample_import_id = '$sample_import_id' + AND q.questionnaire_id = '$questionnaire_id'"; + + $r = $db->GetAll($sql); + + if (empty($r)) + { + print "

    " . T_("Currently no quotas") . "

    "; + } + else + { + foreach($r as $v) + { + print "
    " . T_("Stop calling this sample when:") . " {$v['lime_sgqa']} {$v['comparison']} {$v['value']} " . T_("for") . ": {$v['completions']} " . T_("completions") ." - "; + + if ($v['quota_reached'] == 1) + print T_("Quota reached"); + else + print T_("Quota not yet reached"); + + print " - " . T_("Current completions: ") . limesurvey_quota_completions($v['lime_sgqa'],$v['lime_sid'],$questionnaire_id,$sample_import_id,$v['value'],$v['comparison']); + + print "
    "; + + } + } + + + print "

    " . T_("Select a question for the quota") . "

    "; + + $sql = "SELECT lime_sid + FROM questionnaire + WHERE questionnaire_id = '$questionnaire_id'"; + + $r = $db->GetRow($sql); + + $lime_sid = $r['lime_sid']; + + $sgqa = false; + if (isset($_GET['sgqa'])) $sgqa = $_GET['sgqa']; + + $sql = "SELECT CONCAT( q.sid, 'X', q.gid, 'X', q.qid, IFNULL( a.code, '' ) ) AS value, CONCAT(q.question, ': ', IFNULL(a.answer,'')) as description, CASE WHEN CONCAT( q.sid, 'X', q.gid, 'X', q.qid, IFNULL( a.code, '' ) ) = '$sgqa' THEN 'selected=\'selected\'' ELSE '' END AS selected + FROM `" . LIME_PREFIX . "questions` AS q + LEFT JOIN `" . LIME_PREFIX . "answers` AS a ON ( a.qid = q.qid ) + WHERE q.sid = '$lime_sid'"; + + + display_chooser($ldb->GetAll($sql),"sgqa","sgqa",true,"questionnaire_id=$questionnaire_id&sample_import_id=$sample_import_id"); + + if ($sgqa != false) + { + print "

    " . T_("Enter the details for creating the quota:") . "

    "; + print "

    " . T_("Pre defined values for this question:") . "

    "; + + $qid = explode("X", $sgqa); + $qid = $qid[2]; + + $sql = "SELECT l.code,l.title + FROM `" . LIME_PREFIX . "labels` as l, `" . LIME_PREFIX . "questions` as q + WHERE q.qid = '$qid' + AND l.lid = q.lid"; + + $rs = $ldb->GetAll($sql); + + if (!isset($rs) || empty($rs)) + print "

    " . T_("No labels defined for this question") ."

    "; + else + xhtml_table($rs,array('code','title'),array(T_("Code value"), T_("Description"))); + + + ?> +
    +

    +
    +
    +
    + + + + "/>

    +
    + diff --git a/database/quexs.sql b/database/quexs.sql index c1a6bc66..f8a8759b 100644 --- a/database/quexs.sql +++ b/database/quexs.sql @@ -501,6 +501,23 @@ CREATE TABLE `questionnaire_sample` ( -- Dumping data for table `questionnaire_sample` -- +-- +-- Table structure for table `questionnaire_sample_quota` +-- + +CREATE TABLE IF NOT EXISTS `questionnaire_sample_quota` ( + `questionnaire_sample_quota_id` bigint(20) NOT NULL auto_increment, + `questionnaire_id` bigint(20) NOT NULL, + `sample_import_id` bigint(20) NOT NULL, + `lime_sgqa` varchar(255) collate utf8_unicode_ci NOT NULL, + `value` varchar(2048) collate utf8_unicode_ci NOT NULL, + `comparison` varchar(15) collate utf8_unicode_ci NOT NULL default 'LIKE', + `completions` int(11) NOT NULL, + `quota_reached` tinyint(1) NOT NULL default '0', + PRIMARY KEY (`questionnaire_sample_quota_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + + -- -------------------------------------------------------- diff --git a/functions/functions.limesurvey.php b/functions/functions.limesurvey.php index 7c37b879..ec1ebbe1 100644 --- a/functions/functions.limesurvey.php +++ b/functions/functions.limesurvey.php @@ -43,6 +43,66 @@ include_once(dirname(__FILE__).'/../config.inc.php'); include_once(dirname(__FILE__).'/../db.inc.php'); +/** + * Return the number of completions for a given + * questionnaire, where the given question has + * the given value + * + * @param string $lime_sgqa The limesurvey SGQA + * @param int $lime_sid The limesurvey survey id + * @param int $questionnaire_id The questionnaire ID + * @param int $sample_import_id The sample import ID + * @param string $value The value to compare + * @param string $comparison The type of comparison + * @return bool|int False if failed, otherwise the number of completions + * + */ +function limesurvey_quota_completions($lime_sgqa,$lime_sid,$questionnaire_id,$sample_import_id,$value,$comparison) +{ + global $ldb; + global $db; + + $sql = "SELECT count(*) as c + FROM " . LIME_PREFIX . "survey_$lime_sid + WHERE submitdate IS NOT NULL + AND `$lime_sgqa` $comparison '$value'"; + + $sqm = "SELECT c.case_id as case_id + FROM `case` as c, `sample` as s + WHERE c.questionnaire_id = '$questionnaire_id' + AND c.sample_id = s.sample_id + AND s.import_id = '$sample_import_id'"; + + $r = $db->GetAll($sqm); + + if (!empty($r)) + { + $sql .= " AND ("; + $ccount = count($r); + $ccounter = 0; + foreach($r as $row) + { + $token = $row['case_id']; + $ccounter++; + $sql .= " token = '$token'"; + if ($ccounter < $ccount) + $sql .= " or "; + } + $sql .= ")"; + } + else + return false; + + + $rs = $ldb->GetRow($sql); + + if (isset($rs) && !empty($rs)) + return $rs['c']; + + return false; +} + + /** * Taken from common.php in the LimeSurvey package * Add a prefix to a database name diff --git a/functions/functions.operator.php b/functions/functions.operator.php index 5a101c93..72d49419 100644 --- a/functions/functions.operator.php +++ b/functions/functions.operator.php @@ -275,6 +275,7 @@ function get_case_id($operator_id, $create = false) * 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: @@ -300,6 +301,7 @@ function get_case_id($operator_id, $create = false) 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 LIMIT 1"; @@ -333,6 +335,7 @@ function get_case_id($operator_id, $create = false) WHERE c.case_id is NULL 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 rand() * qs.random_select, s.sample_id LIMIT 1"; @@ -955,6 +958,49 @@ function missed_appointment($call_attempt_id) } +/** + * Check if any quotas apply to this questionnaire + * and if so, update them + * + * @param int $questionnaire_id The questionnaire id + * + */ +function update_quotas($questionnaire_id) +{ + global $db; + + $sql = "SELECT questionnaire_sample_quota_id,q.questionnaire_id,sample_import_id,lime_sgqa,value,comparison,completions,quota_reached,q.lime_sid + FROM questionnaire_sample_quota as qsq, questionnaire as q + WHERE qsq.questionnaire_id = '$questionnaire_id' + AND q.questionnaire_id = '$questionnaire_id'"; + + $rs = $db->GetAll($sql); + + if (isset($rs) && !empty($rs)) + { + //include limesurvey functions + include_once(dirname(__FILE__).'/functions.limesurvey.php'); + + //update all quotas for this questionnaire + foreach($rs as $r) + { + $completions = limesurvey_quota_completions($r['lime_sgqa'],$r['lime_sid'],$r['questionnaire_id'],$r['sample_import_id'],$r['value'],$r['comparison']); + + if ($completions >= $r['completions']) + { + //set quota to reached + $sql = "UPDATE questionnaire_sample_quota + SET quota_reached = '1' + WHERE questionnaire_sample_quota_id = {$r['questionnaire_sample_quota_id']}"; + + $db->Execute($sql); + } + } + } + + return false; +} + /** @@ -963,7 +1009,6 @@ function missed_appointment($call_attempt_id) * @param int $operator_id The operator to end the case for * * @see get_case() - * @todo implement session handling to decrease database requests */ function end_case($operator_id) { @@ -972,6 +1017,7 @@ function end_case($operator_id) $db->StartTrans(); $case_id = get_case_id($operator_id,false); + $questionnaire_id = get_questionnaire_id($operator_id); $return = false; @@ -1077,6 +1123,10 @@ function end_case($operator_id) //the last call is the call with the final otucome $outcome = $a['outcome_id']; $lastcall = $a['call_id']; + + //if the outcome is complete, then update the quota's for this questionnaire (if any) + if ($outcome == 10) + update_quotas($questionnaire_id); } $sql = "UPDATE `case` @@ -1114,7 +1164,7 @@ function outcome_description($outcome_id) $r = $db->CacheGetRow($sql); if (!empty($r)) - return $r['description']; + return T_($r['description']); else return "";