From 20c2fe3e983cdaef9c66f48f0dd841f4bf36e67b Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Thu, 17 Dec 2015 19:09:32 +0800 Subject: [PATCH] MDL-52106 tool_lp: Remove rules when manipulating competencies --- .../lp/amd/build/competencyactions.min.js | 2 +- admin/tool/lp/amd/build/competencytree.min.js | 2 +- admin/tool/lp/amd/src/competencyactions.js | 138 +++++++++++---- admin/tool/lp/amd/src/competencytree.js | 19 +- admin/tool/lp/classes/api.php | 74 ++++++-- admin/tool/lp/classes/competency.php | 11 ++ admin/tool/lp/lang/en/tool_lp.php | 4 + admin/tool/lp/tests/api_test.php | 167 ++++++++++++++++++ 8 files changed, 358 insertions(+), 59 deletions(-) diff --git a/admin/tool/lp/amd/build/competencyactions.min.js b/admin/tool/lp/amd/build/competencyactions.min.js index 221fe49943a..9bfbc25c7a3 100644 --- a/admin/tool/lp/amd/build/competencyactions.min.js +++ b/admin/tool/lp/amd/build/competencyactions.min.js @@ -1 +1 @@ -define(["jquery","core/url","core/templates","core/notification","core/str","core/ajax","tool_lp/dragdrop-reorder","tool_lp/tree","tool_lp/dialogue","tool_lp/menubar","tool_lp/competencypicker","tool_lp/competency_outcomes","tool_lp/competencyruleconfig"],function(a,b,c,d,e,f,g,h,i,j,k,l,m){var n,o,p,q,r,s,t=null,u=null,v=null,w=function(){var c=a('[data-region="competencyactions"]').data("competency"),d={competencyframeworkid:t.getCompetencyFrameworkId(),pagecontextid:n};null!==c&&(d.parentid=c.id);var e=a.param(d);window.location=b.relativeUrl("/admin/tool/lp/editcompetency.php?"+e)},x=function(){if("undefined"==typeof v&&(v=0),v!=u){var b=a('[data-region="filtercompetencies"]').data("frameworkid"),c=f.call([{methodname:"tool_lp_set_parent_competency",args:{competencyid:u,parentid:v}},{methodname:"tool_lp_data_for_competencies_manage_page",args:{competencyframeworkid:b,search:a('[data-region="filtercompetencies"] input').val()}}]);c[1].done(C).fail(d.exception)}},y=function(b){var c=a(b.getContent()),d=c.find("[data-enhance=movetree]"),e=new h(d,!1);e.on("selectionchanged",function(b,c){var d=c.selected;v=a(d).data("id")}),d.show(),c.on("click",'[data-action="move"]',function(){b.close(),x()}),c.on("click",'[data-action="cancel"]',function(){b.close()})},z=function(a,b){var c;for(c=0;cspan",M).on("dragover","li>span",N).on("dragenter","li>span",O).on("dragleave","li>span",P).on("drop","li>span",Q),b.on("selectionchanged",Y),p=new m(t,s),p.on("save",J.bind(this))}}}); \ No newline at end of file +define(["jquery","core/url","core/templates","core/notification","core/str","core/ajax","tool_lp/dragdrop-reorder","tool_lp/tree","tool_lp/dialogue","tool_lp/menubar","tool_lp/competencypicker","tool_lp/competency_outcomes","tool_lp/competencyruleconfig"],function(a,b,c,d,e,f,g,h,i,j,k,l,m){var n,o,p,q,r,s,t=null,u=null,v=null,w=function(){var c=a('[data-region="competencyactions"]').data("competency"),f={competencyframeworkid:t.getCompetencyFrameworkId(),pagecontextid:n};null!==c&&(f.parentid=c.id);var g=function(){var c=a.param(f);window.location=b.relativeUrl("/admin/tool/lp/editcompetency.php?"+c)};null!==c&&t.hasRule(c.id)?e.get_strings([{key:"confirm",component:"moodle"},{key:"addingcompetencywillresetparentrule",component:"tool_lp",param:c.shortname},{key:"yes",component:"core"},{key:"no",component:"core"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],g)}).fail(d.exception):g()},x=function(){var b=a('[data-region="filtercompetencies"]').data("frameworkid"),c=f.call([{methodname:"tool_lp_set_parent_competency",args:{competencyid:u,parentid:v}},{methodname:"tool_lp_data_for_competencies_manage_page",args:{competencyframeworkid:b,search:a('[data-region="filtercompetencies"] input').val()}}]);c[1].done(D).fail(d.exception)},y=function(){if(v="undefined"==typeof v?0:v,v!=u){var a=t.getCompetency(v)||{},b=t.getCompetency(u)||{},c="movecompetencywillresetrules",f=!1;b.parentid!=v&&(a.path&&a.path.indexOf("/"+b.id+"/")>=0&&(c="movecompetencytochildofselfwillresetrules",f=f||t.hasRule(b.id)),f=f||t.hasRule(a.id)||t.hasRule(b.parentid),f?e.get_strings([{key:"confirm",component:"moodle"},{key:c,component:"tool_lp"},{key:"yes",component:"moodle"},{key:"no",component:"moodle"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],x)}).fail(d.exception):x())}},z=function(b){var c=a(b.getContent()),d=c.find("[data-enhance=movetree]"),e=new h(d,!1);e.on("selectionchanged",function(b,c){var d=c.selected;v=a(d).data("id")}),d.show(),c.on("click",'[data-action="move"]',function(){b.close(),y()}),c.on("click",'[data-action="cancel"]',function(){b.close()})},A=function(a,b){var c;for(c=0;cspan",N).on("dragover","li>span",O).on("dragenter","li>span",P).on("dragleave","li>span",Q).on("drop","li>span",R),b.on("selectionchanged",Z),p=new m(t,s),p.on("save",K.bind(this))}}}); \ No newline at end of file diff --git a/admin/tool/lp/amd/build/competencytree.min.js b/admin/tool/lp/amd/build/competencytree.min.js index 6d045efb919..485ccf96fa9 100644 --- a/admin/tool/lp/amd/build/competencytree.min.js +++ b/admin/tool/lp/amd/build/competencytree.min.js @@ -1 +1 @@ -define(["core/ajax","core/notification","core/templates","tool_lp/tree","jquery"],function(a,b,c,d,e){var f={},g=0,h="",i="",j="",k=function(a,b){var c=0,d=!1;for(a.haschildren=!1,a.children=[],c=0;c0},reloadCompetencies:function(){return l("").fail(b.exception)},listCompetencies:function(){return f}}}); \ No newline at end of file +define(["core/ajax","core/notification","core/templates","tool_lp/tree","tool_lp/competency_outcomes","jquery"],function(a,b,c,d,e,f){var g={},h=0,i="",j="",k="",l=function(a,b){var c=0,d=!1;for(a.haschildren=!1,a.children=[],c=0;c0},hasRule:function(a){var b=this.getCompetency(a);return b?b.ruleoutcome!=e.OUTCOME_NONE&&b.ruletype:!1},reloadCompetencies:function(){return m("").fail(b.exception)},listCompetencies:function(){return g}}}); \ No newline at end of file diff --git a/admin/tool/lp/amd/src/competencyactions.js b/admin/tool/lp/amd/src/competencyactions.js index a0d21a5698e..756f519863a 100644 --- a/admin/tool/lp/amd/src/competencyactions.js +++ b/admin/tool/lp/amd/src/competencyactions.js @@ -72,8 +72,30 @@ define(['jquery', // We are adding at a sub node. params.parentid = parent.id; } - var queryparams = $.param(params); - window.location = url.relativeUrl('/admin/tool/lp/editcompetency.php?' + queryparams); + + var relocate = function() { + var queryparams = $.param(params); + window.location = url.relativeUrl('/admin/tool/lp/editcompetency.php?' + queryparams); + }; + + if (parent !== null && treeModel.hasRule(parent.id)) { + str.get_strings([ + { key: 'confirm', component: 'moodle' }, + { key: 'addingcompetencywillresetparentrule', component: 'tool_lp', param: parent.shortname }, + { key: 'yes', component: 'core' }, + { key: 'no', component: 'core' } + ]).done(function (strings) { + notification.confirm( + strings[0], + strings[1], + strings[2], + strings[3], + relocate + ); + }).fail(notification.exception); + } else { + relocate(); + } }; /** @@ -81,14 +103,6 @@ define(['jquery', * @method doMove */ var doMove = function() { - if (typeof (moveTarget) === "undefined") { - // This is a top level node. - moveTarget = 0; - } - - if (moveTarget == moveSource) { - return; - } var frameworkid = $('[data-region="filtercompetencies"]').data('frameworkid'); var requests = ajax.call([{ methodname: 'tool_lp_set_parent_competency', @@ -101,6 +115,61 @@ define(['jquery', requests[1].done(reloadPage).fail(notification.exception); }; + /** + * Confirms a competency move. + * + * @method confirmMove + */ + var confirmMove = function() { + moveTarget = typeof moveTarget === "undefined" ? 0 : moveTarget; + if (moveTarget == moveSource) { + // No move to do. + return; + } + + var targetComp = treeModel.getCompetency(moveTarget) || {}, + sourceComp = treeModel.getCompetency(moveSource) || {}, + confirmMessage = 'movecompetencywillresetrules', + showConfirm = false; + + // We shouldn't be moving the competency to the same parent. + if (sourceComp.parentid == moveTarget) { + return; + } + + // If we are moving to a child of self. + if (targetComp.path && targetComp.path.indexOf('/' + sourceComp.id + '/') >= 0) { + confirmMessage = 'movecompetencytochildofselfwillresetrules'; + + // Show a confirmation if self has rules, as they'll disappear. + showConfirm = showConfirm || treeModel.hasRule(sourceComp.id); + } + + // Show a confirmation if the current parent, or the destination have rules. + showConfirm = showConfirm || (treeModel.hasRule(targetComp.id) || treeModel.hasRule(sourceComp.parentid)); + + // Show confirm, and/or do the things. + if (showConfirm) { + str.get_strings([ + { key: 'confirm', component: 'moodle' }, + { key: confirmMessage, component: 'tool_lp' }, + { key: 'yes', component: 'moodle' }, + { key: 'no', component: 'moodle' } + ]).done(function (strings) { + notification.confirm( + strings[0], // Confirm. + strings[1], // Delete competency X? + strings[2], // Delete. + strings[3], // Cancel. + doMove + ); + }).fail(notification.exception); + + } else { + doMove(); + } + }; + /** * A move competency popup was opened - initialise the aria tree in it. * @method initMovePopup @@ -116,7 +185,7 @@ define(['jquery', }); treeRoot.show(); - body.on('click', '[data-action="move"]', function() { popup.close(); doMove(); }); + body.on('click', '[data-action="move"]', function() { popup.close(); confirmMove(); }); body.on('click', '[data-action="cancel"]', function() { popup.close(); }); }; @@ -144,7 +213,8 @@ define(['jquery', * A node was chosen and "Move" was selected from the menu. Open a popup to select the target. * @method moveHandler */ - var moveHandler = function() { + var moveHandler = function(e) { + e.preventDefault(); var competency = $('[data-region="competencyactions"]').data('competency'); // Remember what we are moving. @@ -417,31 +487,27 @@ define(['jquery', * @method deleteCompetencyHandler */ var deleteCompetencyHandler = function() { - var competency = $('[data-region="competencyactions"]').data('competency'); + var competency = $('[data-region="competencyactions"]').data('competency'), + confirmMessage = 'deletecompetency'; - var context = { - competency: competency - }; - - templates.render('tool_lp/competency_summary', context) - .done(function(html) { - - str.get_strings([ - { key: 'confirm', component: 'moodle' }, - { key: 'deletecompetency', component: 'tool_lp', param: html }, - { key: 'delete', component: 'moodle' }, - { key: 'cancel', component: 'moodle' } - ]).done(function (strings) { - notification.confirm( - strings[0], // Confirm. - strings[1], // Delete competency X? - strings[2], // Delete. - strings[3], // Cancel. - doDelete - ); - }).fail(notification.exception); - }).fail(notification.exception); + if (treeModel.hasRule(competency.parentid)) { + confirmMessage = 'deletecompetencyparenthasrule'; + } + str.get_strings([ + { key: 'confirm', component: 'moodle' }, + { key: confirmMessage, component: 'tool_lp', param: competency.shortname }, + { key: 'delete', component: 'moodle' }, + { key: 'cancel', component: 'moodle' } + ]).done(function (strings) { + notification.confirm( + strings[0], // Confirm. + strings[1], // Delete competency X? + strings[2], // Delete. + strings[3], // Cancel. + doDelete + ); + }).fail(notification.exception); }; /** @@ -489,7 +555,7 @@ define(['jquery', moveTarget = $(e.target).parent().data('id'); $(this).removeClass('currentdragtarget'); - doMove(); + confirmMove(); }; /** diff --git a/admin/tool/lp/amd/src/competencytree.js b/admin/tool/lp/amd/src/competencytree.js index a90abdb85bf..1c6a39311da 100644 --- a/admin/tool/lp/amd/src/competencytree.js +++ b/admin/tool/lp/amd/src/competencytree.js @@ -21,8 +21,8 @@ * @copyright 2015 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -define(['core/ajax', 'core/notification', 'core/templates', 'tool_lp/tree', 'jquery'], - function(ajax, notification, templates, Ariatree, $) { +define(['core/ajax', 'core/notification', 'core/templates', 'tool_lp/tree', 'tool_lp/competency_outcomes', 'jquery'], + function(ajax, notification, templates, Ariatree, CompOutcomes, $) { // Private variables and functions. /** @var {Object[]} competencies - Cached list of competencies */ @@ -220,6 +220,21 @@ define(['core/ajax', 'core/notification', 'core/templates', 'tool_lp/tree', 'jqu return this.getChildren(id).length > 0; }, + /** + * Does the competency have a rule? + * + * @param {Number} id The competency ID. + * @return {Boolean} + */ + hasRule: function(id) { + var comp = this.getCompetency(id); + if (comp) { + return comp.ruleoutcome != CompOutcomes.OUTCOME_NONE + && comp.ruletype; + } + return false; + }, + /** * Reload all the page competencies framework competencies. * @method reloadCompetencies diff --git a/admin/tool/lp/classes/api.php b/admin/tool/lp/classes/api.php index 4112e53e571..e316307e82c 100644 --- a/admin/tool/lp/classes/api.php +++ b/admin/tool/lp/classes/api.php @@ -85,9 +85,15 @@ class api { // Reset the sortorder, use reorder instead. $competency->set_sortorder(null); + $competency->create(); + + // Reset the rule of the parent. + $parent = $competency->get_parent(); + if ($parent) { + $parent->reset_rule(); + $parent->update(); + } - // OK - all set. - $id = $competency->create(); return $competency; } @@ -105,6 +111,13 @@ class api { // First we do a permissions check. require_capability('tool/lp:competencymanage', $competency->get_context()); + // Reset the rule of the parent. + $parent = $competency->get_parent(); + if ($parent) { + $parent->reset_rule(); + $parent->update(); + } + // OK - all set. return $competency->delete(); } @@ -195,39 +208,62 @@ class api { * @return boolean */ public static function set_parent_competency($id, $newparentid) { + global $DB; $current = new competency($id); // First we do a permissions check. require_capability('tool/lp:competencymanage', $current->get_context()); - - // This will throw an exception if the parent does not exist. - - // Check the current one too. - $parentframeworkid = $current->get_competencyframeworkid(); - $parentpath = '/0/'; - if ($newparentid) { - $parent = new competency($newparentid); - $parentframeworkid = $parent->get_competencyframeworkid(); - $parentpath = $parent->get_path(); + if ($id == $newparentid) { + throw new coding_exception('Can not set a competency as a parent of itself.'); + } if ($newparentid == $current->get_parentid()) { + throw new coding_exception('Can not move a competency to the same location.'); } - // If we are moving a node to a child of itself, promote all the child nodes by one level. + // Some great variable assignment right here. + $currentparent = $current->get_parent(); + $parent = !empty($newparentid) ? new competency($newparentid) : null; + $parentpath = !empty($parent) ? $parent->get_path() : '/0/'; + // We're going to change quite a few things. + $transaction = $DB->start_delegated_transaction(); + + // If we are moving a node to a child of itself: + // - promote all the child nodes by one level. + // - remove the rule on self. + // - re-read the parent. $newparents = explode('/', $parentpath); if (in_array($current->get_id(), $newparents)) { - $filters = array('parentid' => $current->get_id(), 'competencyframeworkid' => $current->get_competencyframeworkid()); - $children = self::list_competencies($filters, 'id'); - + $children = competency::get_records(array('parentid' => $current->get_id()), 'id'); foreach ($children as $child) { $child->set_parentid($current->get_parentid()); $child->update(); } + + // Reset the rule on self as our children have changed. + $current->reset_rule(); + + // The destination parent is one of our descendants, we need to re-fetch its values (path, parentid). + $parent->read(); } - $current->set_parentid($newparentid); + // Reset the rules of initial parent and destination. + if (!empty($currentparent)) { + $currentparent->reset_rule(); + $currentparent->update(); + } + if (!empty($parent)) { + $parent->reset_rule(); + $parent->update(); + } - // OK - all set. - return $current->update(); + // Do the actual move. + $current->set_parentid($newparentid); + $current->update(); + + // All right, let's commit this. + $transaction->allow_commit(); + + return true; } /** diff --git a/admin/tool/lp/classes/competency.php b/admin/tool/lp/classes/competency.php index 44a8bc9e4a7..549c1b2f336 100644 --- a/admin/tool/lp/classes/competency.php +++ b/admin/tool/lp/classes/competency.php @@ -352,6 +352,17 @@ class competency extends persistent { return $DB->count_records_select(self::TABLE, "id $insql AND parentid = :parentid", $params) == count($ids); } + /** + * Reset the rule. + * + * @return void + */ + public function reset_rule() { + $this->set_ruleoutcome(static::OUTCOME_NONE); + $this->set_ruletype(null); + $this->set_ruleconfig(null); + } + /** * Helper method to set the path. * diff --git a/admin/tool/lp/lang/en/tool_lp.php b/admin/tool/lp/lang/en/tool_lp.php index 90357a673c4..a0df904242c 100644 --- a/admin/tool/lp/lang/en/tool_lp.php +++ b/admin/tool/lp/lang/en/tool_lp.php @@ -25,6 +25,7 @@ $string['actions'] = 'Actions'; $string['addcohorts'] = 'Add cohorts'; $string['addcompetency'] = 'Add competency'; +$string['addingcompetencywillresetparentrule'] = 'Adding a new competency will remove the rule set on \'{$a}\'. Do you want to continue?'; $string['addnewcompetency'] = 'Add new competency'; $string['addnewcompetencyframework'] = 'Add new competency framework'; $string['addnewplan'] = 'Add new learning plan'; @@ -69,6 +70,7 @@ $string['coveragesummary'] = '{$a->competenciescoveredcount} of {$a->competencie $string['createplans'] = 'Create plans'; $string['default'] = 'Default'; $string['deletecompetency'] = 'Delete competency \'{$a}\'?'; +$string['deletecompetencyparenthasrule'] = 'Delete competency \'{$a}\'? This will also remove the rule set on its parent.'; $string['deletecompetencyframework'] = 'Delete competency framework \'{$a}\'?'; $string['deleteplan'] = 'Delete plan \'{$a}\'?'; $string['deletetemplate'] = 'Delete learning plan template \'{$a}\'?'; @@ -154,6 +156,8 @@ $string['move'] = 'Move'; $string['movecompetency'] = 'Move competency'; $string['movecompetencyafter'] = 'Move competency after \'{$a}\''; $string['movecompetencyframework'] = 'Move competency framework'; +$string['movecompetencywillresetrules'] = 'Moving the competency will remove the rules set on its parent and destination. Do you want to continune?'; +$string['movecompetencytochildofselfwillresetrules'] = 'Moving the competency will remove its own rule, and the rules set on its parent and destination. Do you want to continune?'; $string['moveframeworkafter'] = 'Move competency framework after \'{$a}\''; $string['movetonewparent'] = 'Relocate'; $string['myplans'] = 'My plans'; diff --git a/admin/tool/lp/tests/api_test.php b/admin/tool/lp/tests/api_test.php index d250df616ad..8eba5602a73 100644 --- a/admin/tool/lp/tests/api_test.php +++ b/admin/tool/lp/tests/api_test.php @@ -26,6 +26,7 @@ defined('MOODLE_INTERNAL') || die(); global $CFG; use tool_lp\api; +use tool_lp\competency; use tool_lp\evidence; use tool_lp\user_competency; @@ -1853,4 +1854,170 @@ class tool_lp_api_testcase extends advanced_testcase { } $this->assertEquals(0, count(array_diff($ucp1, $ucp2))); } + + protected function setup_framework_for_reset_rules_tests() { + $this->resetAfterTest(true); + $dg = $this->getDataGenerator(); + $lpg = $dg->get_plugin_generator('tool_lp'); + + $this->setAdminUser(); + $f1 = $lpg->create_framework(); + $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id())); + $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c1->get_id())); + $c1a1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c1a->get_id())); + $c1a1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c1a1->get_id())); + $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id())); + $c1b1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c1b->get_id())); + $c1b1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c1b1->get_id())); + $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id())); + $c2a = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id())); + + $c1->set_ruleoutcome(competency::OUTCOME_EVIDENCE); + $c1->set_ruletype('tool_lp\\competency_rule_all'); + $c1->update(); + $c1a->set_ruleoutcome(competency::OUTCOME_EVIDENCE); + $c1a->set_ruletype('tool_lp\\competency_rule_all'); + $c1a->update(); + $c1a1->set_ruleoutcome(competency::OUTCOME_EVIDENCE); + $c1a1->set_ruletype('tool_lp\\competency_rule_all'); + $c1a1->update(); + $c1b->set_ruleoutcome(competency::OUTCOME_EVIDENCE); + $c1b->set_ruletype('tool_lp\\competency_rule_all'); + $c1b->update(); + $c2->set_ruleoutcome(competency::OUTCOME_EVIDENCE); + $c2->set_ruletype('tool_lp\\competency_rule_all'); + $c2->update(); + + return array( + 'f1' => $f1, + 'c1' => $c1, + 'c1a' => $c1a, + 'c1a1' => $c1a1, + 'c1a1a' => $c1a1a, + 'c1b' => $c1b, + 'c1b1' => $c1b1, + 'c1b1a' => $c1b1a, + 'c2' => $c2, + 'c2a' => $c2a, + ); + } + + public function test_moving_competency_reset_rules_updown() { + extract($this->setup_framework_for_reset_rules_tests()); + + // Moving up and down doesn't change anything. + api::move_down_competency($c1a->get_id()); + $c1->read(); + $c1a->read(); + $c1a1->read(); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get_ruleoutcome()); + api::move_up_competency($c1a->get_id()); + $c1->read(); + $c1a->read(); + $c1a1->read(); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get_ruleoutcome()); + } + + public function test_moving_competency_reset_rules_parent() { + extract($this->setup_framework_for_reset_rules_tests()); + + // Moving out of parent will reset the parent, and the destination. + api::set_parent_competency($c1a->get_id(), $c1b->get_id()); + $c1->read(); + $c1a->read(); + $c1a1->read(); + $c1b->read(); + $c2->read(); + $this->assertEquals(competency::OUTCOME_NONE, $c1->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_NONE, $c1b->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get_ruleoutcome()); + } + + public function test_moving_competency_reset_rules_totoplevel() { + extract($this->setup_framework_for_reset_rules_tests()); + + // Moving to top level only affects the initial parent. + api::set_parent_competency($c1a1->get_id(), 0); + $c1->read(); + $c1a->read(); + $c1a1->read(); + $c1b->read(); + $c2->read(); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_NONE, $c1a->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get_ruleoutcome()); + } + + public function test_moving_competency_reset_rules_fromtoplevel() { + extract($this->setup_framework_for_reset_rules_tests()); + + // Moving from top level only affects the destination parent. + api::set_parent_competency($c2->get_id(), $c1a1->get_id()); + $c1->read(); + $c1a->read(); + $c1a1->read(); + $c1b->read(); + $c2->read(); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_NONE, $c1a1->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get_ruleoutcome()); + } + + public function test_moving_competency_reset_rules_child() { + extract($this->setup_framework_for_reset_rules_tests()); + + // Moving to a child of self resets self, parent and destination. + api::set_parent_competency($c1a->get_id(), $c1a1->get_id()); + $c1->read(); + $c1a->read(); + $c1a1->read(); + $c1b->read(); + $c2->read(); + $this->assertEquals(competency::OUTCOME_NONE, $c1->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_NONE, $c1a->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_NONE, $c1a1->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get_ruleoutcome()); + } + + public function test_create_competency_reset_rules() { + extract($this->setup_framework_for_reset_rules_tests()); + + // Adding a new competency resets the rule of its parent. + api::create_competency((object) array('shortname' => 'A', 'parentid' => $c1->get_id(), 'idnumber' => 'A', + 'competencyframeworkid' => $f1->get_id())); + $c1->read(); + $c1a->read(); + $c1a1->read(); + $c1b->read(); + $c2->read(); + $this->assertEquals(competency::OUTCOME_NONE, $c1->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get_ruleoutcome()); + } + + public function test_delete_competency_reset_rules() { + extract($this->setup_framework_for_reset_rules_tests()); + + // Deleting a competency resets the rule of its parent. + api::delete_competency($c1a->get_id()); + $c1->read(); + $c1b->read(); + $c2->read(); + $this->assertEquals(competency::OUTCOME_NONE, $c1->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get_ruleoutcome()); + $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get_ruleoutcome()); + } }