MDL-55043 core_competency: Sort by id to ensure we get expected result.
[moodle.git] / competency / tests / api_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * API tests.
19  *
20  * @package    core_competency
21  * @copyright  2015 Frédéric Massart - FMCorz.net
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 defined('MOODLE_INTERNAL') || die();
26 global $CFG;
28 use core_competency\api;
29 use core_competency\competency;
30 use core_competency\competency_framework;
31 use core_competency\course_competency_settings;
32 use core_competency\evidence;
33 use core_competency\user_competency;
34 use core_competency\plan;
36 /**
37  * API tests.
38  *
39  * @package    core_competency
40  * @copyright  2015 Frédéric Massart - FMCorz.net
41  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
42  */
43 class core_competency_api_testcase extends advanced_testcase {
45     public function test_get_framework_related_contexts() {
46         $this->resetAfterTest(true);
47         $dg = $this->getDataGenerator();
48         $cat1 = $dg->create_category();
49         $cat2 = $dg->create_category(array('parent' => $cat1->id));
50         $cat3 = $dg->create_category(array('parent' => $cat2->id));
51         $c1 = $dg->create_course(array('category' => $cat2->id));   // This context should not be returned.
53         $cat1ctx = context_coursecat::instance($cat1->id);
54         $cat2ctx = context_coursecat::instance($cat2->id);
55         $cat3ctx = context_coursecat::instance($cat3->id);
56         $sysctx = context_system::instance();
58         $expected = array($cat1ctx->id => $cat1ctx);
59         $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'self'));
61         $expected = array($cat1ctx->id => $cat1ctx, $cat2ctx->id => $cat2ctx, $cat3ctx->id => $cat3ctx);
62         $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'children'));
64         $expected = array($sysctx->id => $sysctx, $cat1ctx->id => $cat1ctx, $cat2ctx->id => $cat2ctx);
65         $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'parents'));
66     }
68     public function test_get_framework_related_contexts_with_capabilities() {
69         $this->resetAfterTest(true);
70         $dg = $this->getDataGenerator();
71         $user = $dg->create_user();
72         $cat1 = $dg->create_category();
73         $cat2 = $dg->create_category(array('parent' => $cat1->id));
74         $cat3 = $dg->create_category(array('parent' => $cat2->id));
75         $c1 = $dg->create_course(array('category' => $cat2->id));   // This context should not be returned.
77         $cat1ctx = context_coursecat::instance($cat1->id);
78         $cat2ctx = context_coursecat::instance($cat2->id);
79         $cat3ctx = context_coursecat::instance($cat3->id);
80         $sysctx = context_system::instance();
82         $roleallow = create_role('Allow', 'allow', 'Allow read');
83         assign_capability('moodle/competency:competencyview', CAP_ALLOW, $roleallow, $sysctx->id);
84         role_assign($roleallow, $user->id, $sysctx->id);
86         $roleprevent = create_role('Prevent', 'prevent', 'Prevent read');
87         assign_capability('moodle/competency:competencyview', CAP_PROHIBIT, $roleprevent, $sysctx->id);
88         role_assign($roleprevent, $user->id, $cat2ctx->id);
90         accesslib_clear_all_caches_for_unit_testing();
91         $this->setUser($user);
92         $this->assertFalse(has_capability('moodle/competency:competencyview', $cat2ctx));
94         $requiredcap = array('moodle/competency:competencyview');
96         $expected = array();
97         $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'self', $requiredcap));
99         $expected = array($cat1ctx->id => $cat1ctx);
100         $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'children', $requiredcap));
102         $expected = array($sysctx->id => $sysctx, $cat1ctx->id => $cat1ctx);
103         $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'parents', $requiredcap));
104     }
106     public function test_get_template_related_contexts() {
107         $this->resetAfterTest(true);
108         $dg = $this->getDataGenerator();
109         $cat1 = $dg->create_category();
110         $cat2 = $dg->create_category(array('parent' => $cat1->id));
111         $cat3 = $dg->create_category(array('parent' => $cat2->id));
112         $c1 = $dg->create_course(array('category' => $cat2->id));   // This context should not be returned.
114         $cat1ctx = context_coursecat::instance($cat1->id);
115         $cat2ctx = context_coursecat::instance($cat2->id);
116         $cat3ctx = context_coursecat::instance($cat3->id);
117         $sysctx = context_system::instance();
119         $expected = array($cat1ctx->id => $cat1ctx);
120         $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'self'));
122         $expected = array($cat1ctx->id => $cat1ctx, $cat2ctx->id => $cat2ctx, $cat3ctx->id => $cat3ctx);
123         $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'children'));
125         $expected = array($sysctx->id => $sysctx, $cat1ctx->id => $cat1ctx, $cat2ctx->id => $cat2ctx);
126         $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'parents'));
127     }
129     public function test_get_template_related_contexts_with_capabilities() {
130         $this->resetAfterTest(true);
131         $dg = $this->getDataGenerator();
132         $user = $dg->create_user();
133         $cat1 = $dg->create_category();
134         $cat2 = $dg->create_category(array('parent' => $cat1->id));
135         $cat3 = $dg->create_category(array('parent' => $cat2->id));
136         $c1 = $dg->create_course(array('category' => $cat2->id));   // This context should not be returned.
138         $cat1ctx = context_coursecat::instance($cat1->id);
139         $cat2ctx = context_coursecat::instance($cat2->id);
140         $cat3ctx = context_coursecat::instance($cat3->id);
141         $sysctx = context_system::instance();
143         $roleallow = create_role('Allow', 'allow', 'Allow read');
144         assign_capability('moodle/competency:templateview', CAP_ALLOW, $roleallow, $sysctx->id);
145         role_assign($roleallow, $user->id, $sysctx->id);
147         $roleprevent = create_role('Prevent', 'prevent', 'Prevent read');
148         assign_capability('moodle/competency:templateview', CAP_PROHIBIT, $roleprevent, $sysctx->id);
149         role_assign($roleprevent, $user->id, $cat2ctx->id);
151         accesslib_clear_all_caches_for_unit_testing();
152         $this->setUser($user);
153         $this->assertFalse(has_capability('moodle/competency:templateview', $cat2ctx));
155         $requiredcap = array('moodle/competency:templateview');
157         $expected = array();
158         $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'self', $requiredcap));
160         $expected = array($cat1ctx->id => $cat1ctx);
161         $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'children', $requiredcap));
163         $expected = array($sysctx->id => $sysctx, $cat1ctx->id => $cat1ctx);
164         $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'parents', $requiredcap));
165     }
167     /**
168      * Test updating a template.
169      */
170     public function test_update_template() {
171         $cat = $this->getDataGenerator()->create_category();
172         $this->resetAfterTest(true);
173         $this->setAdminUser();
175         $syscontext = context_system::instance();
176         $template = api::create_template((object) array('shortname' => 'testing', 'contextid' => $syscontext->id));
178         $this->assertEquals('testing', $template->get_shortname());
179         $this->assertEquals($syscontext->id, $template->get_contextid());
181         // Simple update.
182         api::update_template((object) array('id' => $template->get_id(), 'shortname' => 'success'));
183         $template = api::read_template($template->get_id());
184         $this->assertEquals('success', $template->get_shortname());
186         // Trying to change the context.
187         $this->setExpectedException('coding_exception');
188         api::update_template((object) array('id' => $template->get_id(), 'contextid' => context_coursecat::instance($cat->id)));
189     }
191     /**
192      * Test listing framework with order param.
193      */
194     public function test_list_frameworks() {
195         $this->resetAfterTest(true);
196         $this->setAdminUser();
197         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
199         // Create a list of frameworks.
200         $framework1 = $lpg->create_framework(array(
201             'shortname' => 'shortname_alpha',
202             'idnumber' => 'idnumber_cinnamon',
203             'description' => 'description',
204             'descriptionformat' => FORMAT_HTML,
205             'visible' => true,
206             'contextid' => context_system::instance()->id
207         ));
209         $framework2 = $lpg->create_framework(array(
210             'shortname' => 'shortname_beetroot',
211             'idnumber' => 'idnumber_apple',
212             'description' => 'description',
213             'descriptionformat' => FORMAT_HTML,
214             'visible' => true,
215             'contextid' => context_system::instance()->id
216         ));
218         $framework3 = $lpg->create_framework(array(
219             'shortname' => 'shortname_crisps',
220             'idnumber' => 'idnumber_beer',
221             'description' => 'description',
222             'descriptionformat' => FORMAT_HTML,
223             'visible' => false,
224             'contextid' => context_system::instance()->id
225         ));
227         // Get frameworks list order by shortname desc.
228         $result = api::list_frameworks('shortname', 'DESC', null, 3, context_system::instance());
230         $f = (object) array_shift($result);
231         $this->assertEquals($framework3->get_id(), $f->get_id());
232         $f = (object) array_shift($result);
233         $this->assertEquals($framework2->get_id(), $f->get_id());
234         $f = (object) array_shift($result);
235         $this->assertEquals($framework1->get_id(), $f->get_id());
237         // Get frameworks list order by idnumber asc.
238         $result = api::list_frameworks('idnumber', 'ASC', null, 3, context_system::instance());
240         $f = (object) array_shift($result);
241         $this->assertEquals($framework2->get_id(), $f->get_id());
242         $f = (object) array_shift($result);
243         $this->assertEquals($framework3->get_id(), $f->get_id());
244         $f = (object) array_shift($result);
245         $this->assertEquals($framework1->get_id(), $f->get_id());
247         // Repeat excluding the non-visible ones.
248         $result = api::list_frameworks('idnumber', 'ASC', null, 3, context_system::instance(), 'self', true);
249         $this->assertCount(2, $result);
250         $f = (object) array_shift($result);
251         $this->assertEquals($framework2->get_id(), $f->get_id());
252         $f = (object) array_shift($result);
253         $this->assertEquals($framework1->get_id(), $f->get_id());
255         // Search by query string, trying match on shortname.
256         $result = api::list_frameworks('idnumber', 'ASC', null, 3, context_system::instance(), 'self', false, 'crisp');
257         $this->assertCount(1, $result);
258         $f = (object) array_shift($result);
259         $this->assertEquals($framework3->get_id(), $f->get_id());
261         // Search by query string, trying match on shortname, but hidden.
262         $result = api::list_frameworks('idnumber', 'ASC', null, 3, context_system::instance(), 'self', true, 'crisp');
263         $this->assertCount(0, $result);
265         // Search by query string, trying match on ID number.
266         $result = api::list_frameworks('idnumber', 'ASC', null, 3, context_system::instance(), 'self', false, 'apple');
267         $this->assertCount(1, $result);
268         $f = (object) array_shift($result);
269         $this->assertEquals($framework2->get_id(), $f->get_id());
271         // Search by query string, trying match on both.
272         $result = api::list_frameworks('idnumber', 'ASC', null, 3, context_system::instance(), 'self', false, 'bee');
273         $this->assertCount(2, $result);
274         $f = (object) array_shift($result);
275         $this->assertEquals($framework2->get_id(), $f->get_id());
276         $f = (object) array_shift($result);
277         $this->assertEquals($framework3->get_id(), $f->get_id());
278     }
280     /**
281      * Test duplicate a framework.
282      */
283     public function test_duplicate_framework() {
284         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
285         $this->resetAfterTest(true);
286         $this->setAdminUser();
288         $syscontext = context_system::instance();
289         $params = array(
290                 'shortname' => 'shortname_a',
291                 'idnumber' => 'idnumber_c',
292                 'description' => 'description',
293                 'descriptionformat' => FORMAT_HTML,
294                 'visible' => true,
295                 'contextid' => $syscontext->id
296         );
297         $framework = $lpg->create_framework($params);
298         $competency1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
299         $competency2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
300         $competency3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
301         $competency4 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
302         $competency41 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id(),
303                                                         'parentid' => $competency4->get_id())
304                                                     );
305         $competency42 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id(),
306                                                         'parentid' => $competency4->get_id())
307                                                     );
308         $competencyidnumbers = array($competency1->get_idnumber(),
309                                         $competency2->get_idnumber(),
310                                         $competency3->get_idnumber(),
311                                         $competency4->get_idnumber(),
312                                         $competency41->get_idnumber(),
313                                         $competency42->get_idnumber()
314                                     );
316         $config = json_encode(array(
317             'base' => array('points' => 4),
318             'competencies' => array(
319                 array('id' => $competency41->get_id(), 'points' => 3, 'required' => 0),
320                 array('id' => $competency42->get_id(), 'points' => 2, 'required' => 1),
321             )
322         ));
323         $competency4->set_ruletype('core_competency\competency_rule_points');
324         $competency4->set_ruleoutcome(\core_competency\competency::OUTCOME_EVIDENCE);
325         $competency4->set_ruleconfig($config);
326         $competency4->update();
328         api::add_related_competency($competency1->get_id(), $competency2->get_id());
329         api::add_related_competency($competency3->get_id(), $competency4->get_id());
331         $frameworkduplicated1 = api::duplicate_framework($framework->get_id());
332         $frameworkduplicated2 = api::duplicate_framework($framework->get_id());
334         $this->assertEquals($framework->get_idnumber().'_1', $frameworkduplicated1->get_idnumber());
335         $this->assertEquals($framework->get_idnumber().'_2', $frameworkduplicated2->get_idnumber());
337         $competenciesfr1 = api::list_competencies(array('competencyframeworkid' => $frameworkduplicated1->get_id()));
338         $competenciesfr2 = api::list_competencies(array('competencyframeworkid' => $frameworkduplicated2->get_id()));
340         $competencyidsfr1 = array();
341         $competencyidsfr2 = array();
343         foreach ($competenciesfr1 as $cmp) {
344             $competencyidsfr1[] = $cmp->get_idnumber();
345         }
346         foreach ($competenciesfr2 as $cmp) {
347             $competencyidsfr2[] = $cmp->get_idnumber();
348         }
350         $this->assertEmpty(array_diff($competencyidsfr1, $competencyidnumbers));
351         $this->assertEmpty(array_diff($competencyidsfr2, $competencyidnumbers));
352         $this->assertCount(6, $competenciesfr1);
353         $this->assertCount(6, $competenciesfr2);
355         // Test the related competencies.
356         reset($competenciesfr1);
357         $compduplicated1 = current($competenciesfr1);
358         $relatedcompetencies = $compduplicated1->get_related_competencies();
359         $comprelated = current($relatedcompetencies);
360         $this->assertEquals($comprelated->get_idnumber(), $competency2->get_idnumber());
362         // Check if config rule have been ported correctly.
363         $competency4duplicated = competency::get_record(array(
364                                                             'idnumber' => $competency4->get_idnumber(),
365                                                             'competencyframeworkid' => $frameworkduplicated2->get_id()
366                                                         ));
367         $configduplicated = json_decode($competency4duplicated->get_ruleconfig(), true);
368         $configorigin = json_decode($config, true);
369         // Check that the 2 config have the same base.
370         $this->assertEquals($configorigin['base'], $configduplicated['base']);
371         $this->assertEquals(count($configorigin['competencies']), count($configduplicated['competencies']));
372         $competencyidsrules = array();
373         foreach ($configduplicated['competencies'] as $key => $value) {
374             // Check that the only difference between the 2 config is id competency.
375             $this->assertEquals(1, count(array_diff($value, $configorigin['competencies'][$key])));
376             $competencyidsrules[] = $value['id'];
377         }
378         $this->assertTrue($competency4duplicated->is_parent_of($competencyidsrules));
380         // Test duplicate an empty framework.
381         $emptyfrm = $lpg->create_framework();
382         $emptyfrmduplicated = api::duplicate_framework($emptyfrm->get_id());
383         $this->assertEquals($emptyfrm->get_idnumber().'_1', $emptyfrmduplicated->get_idnumber());
384         $nbcomp = api::count_competencies(array('competencyframeworkid' => $emptyfrmduplicated->get_id()));
385         $this->assertEquals(0, $nbcomp);
387     }
389     /**
390      * Test update plan.
391      */
392     public function test_update_plan() {
393         $this->resetAfterTest(true);
394         $dg = $this->getDataGenerator();
395         $usermanageowndraft = $dg->create_user();
396         $usermanageown = $dg->create_user();
397         $usermanagedraft = $dg->create_user();
398         $usermanage = $dg->create_user();
400         $syscontext = context_system::instance();
402         // Creating specific roles.
403         $manageowndraftrole = $dg->create_role(array(
404             'name' => 'User manage own draft',
405             'shortname' => 'manage-own-draft'
406         ));
407         $manageownrole = $dg->create_role(array(
408             'name' => 'User manage own',
409             'shortname' => 'manage-own'
410         ));
411         $managedraftrole = $dg->create_role(array(
412             'name' => 'User manage draft',
413             'shortname' => 'manage-draft'
414         ));
415         $managerole = $dg->create_role(array(
416             'name' => 'User manage',
417             'shortname' => 'manage'
418         ));
420         assign_capability('moodle/competency:planmanageowndraft', CAP_ALLOW, $manageowndraftrole, $syscontext->id);
421         assign_capability('moodle/competency:planviewowndraft', CAP_ALLOW, $manageowndraftrole, $syscontext->id);
423         assign_capability('moodle/competency:planmanageown', CAP_ALLOW, $manageownrole, $syscontext->id);
424         assign_capability('moodle/competency:planviewown', CAP_ALLOW, $manageownrole, $syscontext->id);
426         assign_capability('moodle/competency:planmanagedraft', CAP_ALLOW, $managedraftrole, $syscontext->id);
427         assign_capability('moodle/competency:planviewdraft', CAP_ALLOW, $managedraftrole, $syscontext->id);
429         assign_capability('moodle/competency:planmanage', CAP_ALLOW, $managerole, $syscontext->id);
430         assign_capability('moodle/competency:planview', CAP_ALLOW, $managerole, $syscontext->id);
432         $dg->role_assign($manageowndraftrole, $usermanageowndraft->id, $syscontext->id);
433         $dg->role_assign($manageownrole, $usermanageown->id, $syscontext->id);
434         $dg->role_assign($managedraftrole, $usermanagedraft->id, $syscontext->id);
435         $dg->role_assign($managerole, $usermanage->id, $syscontext->id);
437         // Create first learning plan with user create draft.
438         $this->setUser($usermanageowndraft);
439         $plan = array (
440             'name' => 'plan own draft',
441             'description' => 'plan own draft',
442             'userid' => $usermanageowndraft->id
443         );
444         $plan = api::create_plan((object)$plan);
445         $record = $plan->to_record();
446         $record->name = 'plan own draft modified';
448         // Check if user create draft can edit the plan name.
449         $plan = api::update_plan($record);
450         $this->assertInstanceOf('\core_competency\plan', $plan);
452         // The status cannot be changed in this method.
453         $record->status = \core_competency\plan::STATUS_ACTIVE;
454         try {
455             $plan = api::update_plan($record);
456             $this->fail('Updating the status is not allowed.');
457         } catch (coding_exception $e) {
458             $this->assertRegExp('/To change the status of a plan use the appropriate methods./', $e->getMessage());
459         }
461         // Test when user with manage own plan capability try to edit other user plan.
462         $record->status = \core_competency\plan::STATUS_DRAFT;
463         $record->name = 'plan create draft modified 2';
464         $this->setUser($usermanageown);
465         try {
466             $plan = api::update_plan($record);
467             $this->fail('User with manage own plan capability can only edit his own plan.');
468         } catch (required_capability_exception $e) {
469             $this->assertTrue(true);
470         }
472         // User with manage plan capability cannot edit the other user plans with status draft.
473         $this->setUser($usermanage);
474         $record->name = 'plan create draft modified 3';
475         try {
476             $plan = api::update_plan($record);
477             $this->fail('User with manage plan capability cannot edit the other user plans with status draft');
478         } catch (required_capability_exception $e) {
479             $this->assertTrue(true);
480         }
482         // User with manage draft capability can edit other user's learning plan if the status is draft.
483         $this->setUser($usermanagedraft);
484         $record->status = \core_competency\plan::STATUS_DRAFT;
485         $record->name = 'plan manage draft modified 3';
486         $plan = api::update_plan($record);
487         $this->assertInstanceOf('\core_competency\plan', $plan);
489         // User with manage  plan capability can create/edit learning plan if status is active/complete.
490         $this->setUser($usermanage);
491         $plan = array (
492             'name' => 'plan create',
493             'description' => 'plan create',
494             'userid' => $usermanage->id,
495             'status' => \core_competency\plan::STATUS_ACTIVE
496         );
497         $plan = api::create_plan((object)$plan);
499         // Silently transition to complete status to avoid errors about transitioning to complete.
500         $plan->set_status(\core_competency\plan::STATUS_COMPLETE);
501         $plan->update();
503         $record = $plan->to_record();
504         $record->name = 'plan create own modified';
505         try {
506             api::update_plan($record);
507             $this->fail('Completed plan can not be edited');
508         } catch (coding_exception $e) {
509             $this->assertTrue(true);
510         }
511     }
513     public function test_create_plan_from_template() {
514         $this->resetAfterTest(true);
515         $this->setAdminUser();
517         $u1 = $this->getDataGenerator()->create_user();
518         $tpl = $this->getDataGenerator()->get_plugin_generator('core_competency')->create_template();
520         // Creating a new plan.
521         $plan = api::create_plan_from_template($tpl, $u1->id);
522         $record = $plan->to_record();
523         $this->assertInstanceOf('\core_competency\plan', $plan);
524         $this->assertTrue(\core_competency\plan::record_exists($plan->get_id()));
525         $this->assertEquals($tpl->get_id(), $plan->get_templateid());
526         $this->assertEquals($u1->id, $plan->get_userid());
527         $this->assertTrue($plan->is_based_on_template());
529         // Creating a plan that already exists.
530         $plan = api::create_plan_from_template($tpl, $u1->id);
531         $this->assertFalse($plan);
533         // Check that api::create_plan cannot be used.
534         $this->setExpectedException('coding_exception');
535         unset($record->id);
536         $plan = api::create_plan($record);
537     }
539     public function test_update_plan_based_on_template() {
540         $this->resetAfterTest(true);
541         $dg = $this->getDataGenerator();
542         $lpg = $dg->get_plugin_generator('core_competency');
543         $u1 = $dg->create_user();
544         $u2 = $dg->create_user();
546         $this->setAdminUser();
547         $tpl1 = $lpg->create_template();
548         $tpl2 = $lpg->create_template();
549         $up1 = $lpg->create_plan(array('userid' => $u1->id, 'templateid' => $tpl1->get_id()));
550         $up2 = $lpg->create_plan(array('userid' => $u2->id, 'templateid' => null));
552         try {
553             // Trying to remove the template dependency.
554             $record = $up1->to_record();
555             $record->templateid = null;
556             api::update_plan($record);
557             $this->fail('A plan cannot be unlinked using api::update_plan()');
558         } catch (coding_exception $e) {
559             // All good.
560         }
562         try {
563             // Trying to switch to another template.
564             $record = $up1->to_record();
565             $record->templateid = $tpl2->get_id();
566             api::update_plan($record);
567             $this->fail('A plan cannot be moved to another template.');
568         } catch (coding_exception $e) {
569             // All good.
570         }
572         try {
573             // Trying to switch to using a template.
574             $record = $up2->to_record();
575             $record->templateid = $tpl1->get_id();
576             api::update_plan($record);
577             $this->fail('A plan cannot be update to use a template.');
578         } catch (coding_exception $e) {
579             // All good.
580         }
581     }
583     public function test_unlink_plan_from_template() {
584         $this->resetAfterTest(true);
585         $dg = $this->getDataGenerator();
586         $lpg = $dg->get_plugin_generator('core_competency');
587         $u1 = $dg->create_user();
588         $u2 = $dg->create_user();
590         $this->setAdminUser();
591         $f1 = $lpg->create_framework();
592         $f2 = $lpg->create_framework();
593         $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
594         $c2a = $lpg->create_competency(array('competencyframeworkid' => $f2->get_id()));
595         $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
597         $tpl1 = $lpg->create_template();
598         $tpl2 = $lpg->create_template();
600         $tplc1a = $lpg->create_template_competency(array('templateid' => $tpl1->get_id(), 'competencyid' => $c1a->get_id(),
601             'sortorder' => 9));
602         $tplc1b = $lpg->create_template_competency(array('templateid' => $tpl1->get_id(), 'competencyid' => $c1b->get_id(),
603             'sortorder' => 8));
604         $tplc2a = $lpg->create_template_competency(array('templateid' => $tpl2->get_id(), 'competencyid' => $c2a->get_id()));
606         $plan1 = $lpg->create_plan(array('userid' => $u1->id, 'templateid' => $tpl1->get_id(), 'status' => plan::STATUS_ACTIVE));
607         $plan2 = $lpg->create_plan(array('userid' => $u2->id, 'templateid' => $tpl2->get_id()));
608         $plan3 = $lpg->create_plan(array('userid' => $u1->id, 'templateid' => $tpl1->get_id(), 'status' => plan::STATUS_COMPLETE));
610         // Check that we have what we expect at this stage.
611         $this->assertEquals(2, \core_competency\template_competency::count_records(array('templateid' => $tpl1->get_id())));
612         $this->assertEquals(1, \core_competency\template_competency::count_records(array('templateid' => $tpl2->get_id())));
613         $this->assertEquals(0, \core_competency\plan_competency::count_records(array('planid' => $plan1->get_id())));
614         $this->assertEquals(0, \core_competency\plan_competency::count_records(array('planid' => $plan2->get_id())));
615         $this->assertTrue($plan1->is_based_on_template());
616         $this->assertTrue($plan2->is_based_on_template());
618         // Let's do this!
619         $tpl1comps = \core_competency\template_competency::list_competencies($tpl1->get_id(), true);
620         $tpl2comps = \core_competency\template_competency::list_competencies($tpl2->get_id(), true);
622         api::unlink_plan_from_template($plan1);
624         $plan1->read();
625         $plan2->read();
626         $this->assertCount(2, $tpl1comps);
627         $this->assertCount(1, $tpl2comps);
628         $this->assertEquals(2, \core_competency\template_competency::count_records(array('templateid' => $tpl1->get_id())));
629         $this->assertEquals(1, \core_competency\template_competency::count_records(array('templateid' => $tpl2->get_id())));
630         $this->assertEquals(2, \core_competency\plan_competency::count_records(array('planid' => $plan1->get_id())));
631         $this->assertEquals(0, \core_competency\plan_competency::count_records(array('planid' => $plan2->get_id())));
632         $this->assertFalse($plan1->is_based_on_template());
633         $this->assertEquals($tpl1->get_id(), $plan1->get_origtemplateid());
634         $this->assertTrue($plan2->is_based_on_template());
635         $this->assertEquals(null, $plan2->get_origtemplateid());
637         // Check we can unlink draft plan.
638         try {
639             api::unlink_plan_from_template($plan2);
640         } catch (coding_exception $e) {
641             $this->fail('Fail to unlink draft plan.');
642         }
644         // Check we can not unlink completed plan.
645         try {
646             api::unlink_plan_from_template($plan3);
647             $this->fail('We can not unlink completed plan.');
648         } catch (coding_exception $e) {
649             // All good.
650         }
652         // Even the order remains.
653         $plan1comps = \core_competency\plan_competency::list_competencies($plan1->get_id());
654         $before = reset($tpl1comps);
655         $after = reset($plan1comps);
656         $this->assertEquals($before->get_id(), $after->get_id());
657         $this->assertEquals($before->get_sortorder(), $after->get_sortorder());
658         $before = next($tpl1comps);
659         $after = next($plan1comps);
660         $this->assertEquals($before->get_id(), $after->get_id());
661         $this->assertEquals($before->get_sortorder(), $after->get_sortorder());
662     }
664     public function test_update_template_updates_plans() {
665         $this->resetAfterTest(true);
666         $this->setAdminUser();
668         $dg = $this->getDataGenerator();
669         $u1 = $dg->create_user();
670         $u2 = $dg->create_user();
671         $lpg = $dg->get_plugin_generator('core_competency');
672         $tpl1 = $lpg->create_template();
673         $tpl2 = $lpg->create_template();
675         // Create plans with data not matching templates.
676         $time = time();
677         $plan1 = $lpg->create_plan(array('templateid' => $tpl1->get_id(), 'userid' => $u1->id,
678             'name' => 'Not good name', 'duedate' => $time + 3600, 'description' => 'Ahah', 'descriptionformat' => FORMAT_MARKDOWN));
679         $plan2 = $lpg->create_plan(array('templateid' => $tpl1->get_id(), 'userid' => $u2->id,
680             'name' => 'Not right name', 'duedate' => $time + 3601, 'description' => 'Ahah', 'descriptionformat' => FORMAT_PLAIN));
681         $plan3 = $lpg->create_plan(array('templateid' => $tpl2->get_id(), 'userid' => $u1->id,
682             'name' => 'Not sweet name', 'duedate' => $time + 3602, 'description' => 'Ahah', 'descriptionformat' => FORMAT_PLAIN));
684         // Prepare our expectations.
685         $plan1->read();
686         $plan2->read();
687         $plan3->read();
689         $this->assertEquals($tpl1->get_id(), $plan1->get_templateid());
690         $this->assertEquals($tpl1->get_id(), $plan2->get_templateid());
691         $this->assertEquals($tpl2->get_id(), $plan3->get_templateid());
692         $this->assertNotEquals($tpl1->get_shortname(), $plan1->get_name());
693         $this->assertNotEquals($tpl1->get_shortname(), $plan2->get_name());
694         $this->assertNotEquals($tpl2->get_shortname(), $plan3->get_name());
695         $this->assertNotEquals($tpl1->get_description(), $plan1->get_description());
696         $this->assertNotEquals($tpl1->get_description(), $plan2->get_description());
697         $this->assertNotEquals($tpl2->get_description(), $plan3->get_description());
698         $this->assertNotEquals($tpl1->get_descriptionformat(), $plan1->get_descriptionformat());
699         $this->assertNotEquals($tpl1->get_descriptionformat(), $plan2->get_descriptionformat());
700         $this->assertNotEquals($tpl2->get_descriptionformat(), $plan3->get_descriptionformat());
701         $this->assertNotEquals($tpl1->get_duedate(), $plan1->get_duedate());
702         $this->assertNotEquals($tpl1->get_duedate(), $plan2->get_duedate());
703         $this->assertNotEquals($tpl2->get_duedate(), $plan3->get_duedate());
705         // Update the template without changing critical fields does not update the plans.
706         $data = $tpl1->to_record();
707         $data->visible = 0;
708         api::update_template($data);
709         $this->assertNotEquals($tpl1->get_shortname(), $plan1->get_name());
710         $this->assertNotEquals($tpl1->get_shortname(), $plan2->get_name());
711         $this->assertNotEquals($tpl2->get_shortname(), $plan3->get_name());
712         $this->assertNotEquals($tpl1->get_description(), $plan1->get_description());
713         $this->assertNotEquals($tpl1->get_description(), $plan2->get_description());
714         $this->assertNotEquals($tpl2->get_description(), $plan3->get_description());
715         $this->assertNotEquals($tpl1->get_descriptionformat(), $plan1->get_descriptionformat());
716         $this->assertNotEquals($tpl1->get_descriptionformat(), $plan2->get_descriptionformat());
717         $this->assertNotEquals($tpl2->get_descriptionformat(), $plan3->get_descriptionformat());
718         $this->assertNotEquals($tpl1->get_duedate(), $plan1->get_duedate());
719         $this->assertNotEquals($tpl1->get_duedate(), $plan2->get_duedate());
720         $this->assertNotEquals($tpl2->get_duedate(), $plan3->get_duedate());
722         // Now really update the template.
723         $data = $tpl1->to_record();
724         $data->shortname = 'Awesome!';
725         $data->description = 'This is too awesome!';
726         $data->descriptionformat = FORMAT_HTML;
727         $data->duedate = $time + 200;
728         api::update_template($data);
729         $tpl1->read();
731         // Now confirm that the right plans were updated.
732         $plan1->read();
733         $plan2->read();
734         $plan3->read();
736         $this->assertEquals($tpl1->get_id(), $plan1->get_templateid());
737         $this->assertEquals($tpl1->get_id(), $plan2->get_templateid());
738         $this->assertEquals($tpl2->get_id(), $plan3->get_templateid());
740         $this->assertEquals($tpl1->get_shortname(), $plan1->get_name());
741         $this->assertEquals($tpl1->get_shortname(), $plan2->get_name());
742         $this->assertNotEquals($tpl2->get_shortname(), $plan3->get_name());
743         $this->assertEquals($tpl1->get_description(), $plan1->get_description());
744         $this->assertEquals($tpl1->get_description(), $plan2->get_description());
745         $this->assertNotEquals($tpl2->get_description(), $plan3->get_description());
746         $this->assertEquals($tpl1->get_descriptionformat(), $plan1->get_descriptionformat());
747         $this->assertEquals($tpl1->get_descriptionformat(), $plan2->get_descriptionformat());
748         $this->assertNotEquals($tpl2->get_descriptionformat(), $plan3->get_descriptionformat());
749         $this->assertEquals($tpl1->get_duedate(), $plan1->get_duedate());
750         $this->assertEquals($tpl1->get_duedate(), $plan2->get_duedate());
751         $this->assertNotEquals($tpl2->get_duedate(), $plan3->get_duedate());
752     }
754     /**
755      * Test that the method to complete a plan.
756      */
757     public function test_complete_plan() {
758         global $DB;
760         $this->resetAfterTest(true);
761         $this->setAdminUser();
762         $dg = $this->getDataGenerator();
763         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
764         $user = $dg->create_user();
766         // Create a framework and assign competencies.
767         $framework = $lpg->create_framework();
768         $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
769         $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
770         $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
771         $c4 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
773         // Create two plans and assign competencies.
774         $plan = $lpg->create_plan(array('userid' => $user->id));
775         $otherplan = $lpg->create_plan(array('userid' => $user->id));
777         $lpg->create_plan_competency(array('planid' => $plan->get_id(), 'competencyid' => $c1->get_id()));
778         $lpg->create_plan_competency(array('planid' => $plan->get_id(), 'competencyid' => $c2->get_id()));
779         $lpg->create_plan_competency(array('planid' => $plan->get_id(), 'competencyid' => $c3->get_id()));
780         $lpg->create_plan_competency(array('planid' => $otherplan->get_id(), 'competencyid' => $c1->get_id()));
782         $uclist = array(
783             $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c1->get_id(),
784                 'proficiency' => true, 'grade' => 1 )),
785             $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c2->get_id(),
786                 'proficiency' => false, 'grade' => 2 ))
787         );
789         $this->assertEquals(2, \core_competency\user_competency::count_records());
790         $this->assertEquals(0, \core_competency\user_competency_plan::count_records());
792         // Change status of the plan to complete.
793         api::complete_plan($plan);
795         // Check that user competencies are now in user_competency_plan objects and still in user_competency.
796         $this->assertEquals(2, \core_competency\user_competency::count_records());
797         $this->assertEquals(3, \core_competency\user_competency_plan::count_records());
799         $usercompetenciesplan = \core_competency\user_competency_plan::get_records();
801         $this->assertEquals($uclist[0]->get_userid(), $usercompetenciesplan[0]->get_userid());
802         $this->assertEquals($uclist[0]->get_competencyid(), $usercompetenciesplan[0]->get_competencyid());
803         $this->assertEquals($uclist[0]->get_proficiency(), (bool) $usercompetenciesplan[0]->get_proficiency());
804         $this->assertEquals($uclist[0]->get_grade(), $usercompetenciesplan[0]->get_grade());
805         $this->assertEquals($plan->get_id(), $usercompetenciesplan[0]->get_planid());
807         $this->assertEquals($uclist[1]->get_userid(), $usercompetenciesplan[1]->get_userid());
808         $this->assertEquals($uclist[1]->get_competencyid(), $usercompetenciesplan[1]->get_competencyid());
809         $this->assertEquals($uclist[1]->get_proficiency(), (bool) $usercompetenciesplan[1]->get_proficiency());
810         $this->assertEquals($uclist[1]->get_grade(), $usercompetenciesplan[1]->get_grade());
811         $this->assertEquals($plan->get_id(), $usercompetenciesplan[1]->get_planid());
813         $this->assertEquals($user->id, $usercompetenciesplan[2]->get_userid());
814         $this->assertEquals($c3->get_id(), $usercompetenciesplan[2]->get_competencyid());
815         $this->assertNull($usercompetenciesplan[2]->get_proficiency());
816         $this->assertNull($usercompetenciesplan[2]->get_grade());
817         $this->assertEquals($plan->get_id(), $usercompetenciesplan[2]->get_planid());
819         // Check we can not add competency to completed plan.
820         try {
821             api::add_competency_to_plan($plan->get_id(), $c4->get_id());
822             $this->fail('We can not add competency to completed plan.');
823         } catch (coding_exception $e) {
824             // All good.
825         }
827         // Check we can not remove competency to completed plan.
828         try {
829             api::remove_competency_from_plan($plan->get_id(), $c3->get_id());
830             $this->fail('We can not remove competency to completed plan.');
831         } catch (coding_exception $e) {
832             // All good.
833         }
835         // Completing a plan that is completed throws an exception.
836         $this->setExpectedException('coding_exception');
837         api::complete_plan($plan);
838     }
840     /**
841      * Set-up the workflow data (review, active, ...).
842      *
843      * @return array
844      */
845     protected function setup_workflow_data() {
846         $this->resetAfterTest();
848         $dg = $this->getDataGenerator();
849         $user = $dg->create_user();
850         $reviewer = $dg->create_user();
851         $otheruser = $dg->create_user();
853         $syscontext = context_system::instance();
854         $userrole = $dg->create_role();
855         $reviewerrole = $dg->create_role();
856         $otheruserrole = $dg->create_role();
858         assign_capability('moodle/competency:planmanageowndraft', CAP_ALLOW, $userrole, $syscontext->id);
859         assign_capability('moodle/competency:planmanage', CAP_ALLOW, $reviewerrole, $syscontext->id);
860         assign_capability('moodle/competency:planviewdraft', CAP_ALLOW, $reviewerrole, $syscontext->id);
861         $dg->role_assign($userrole, $user->id, $syscontext->id);
862         $dg->role_assign($reviewerrole, $reviewer->id, $syscontext->id);
863         accesslib_clear_all_caches_for_unit_testing();
865         $lpg = $dg->get_plugin_generator('core_competency');
866         $tpl = $lpg->create_template();
867         $plan = $lpg->create_plan(array('userid' => $user->id));
868         $tplplan = $lpg->create_plan(array('userid' => $user->id, 'templateid' => $tpl->get_id()));
870         return array(
871             'dg' => $dg,
872             'lpg' => $lpg,
873             'user' => $user,
874             'reviewer' => $reviewer,
875             'otheruser' => $otheruser,
876             'plan' => $plan,
877             'tplplan' => $tplplan,
878         );
879     }
881     /**
882      * Testing requesting the review of a plan.
883      */
884     public function test_plan_request_review() {
885         $data = $this->setup_workflow_data();
886         $dg = $data['dg'];
887         $lpg = $data['lpg'];
888         $user = $data['user'];
889         $reviewer = $data['reviewer'];
890         $otheruser = $data['otheruser'];
891         $plan = $data['plan'];
892         $tplplan = $data['tplplan'];
894         $this->assertEquals(plan::STATUS_DRAFT, $plan->get_status());
895         $this->assertEquals(plan::STATUS_DRAFT, $tplplan->get_status());
897         // Foreign user cannot do anything.
898         $this->setUser($otheruser);
899         try {
900             api::plan_request_review($plan);
901             $this->fail('The user can not read the plan.');
902         } catch (required_capability_exception $e) {
903             $this->assertEquals('nopermissions', $e->errorcode);
904         }
906         // Can not change a plan based on a template.
907         $this->setUser($user);
908         try {
909             api::plan_request_review($tplplan);
910             $this->fail('The plan is based on a template.');
911         } catch (coding_exception $e) {
912             $this->assertRegExp('/Template plans cannot be reviewed./', $e->getMessage());
913         }
915         // Can not send for review when not draft.
916         $this->setUser($user);
917         $plan->set_status(plan::STATUS_WAITING_FOR_REVIEW);
918         try {
919             api::plan_request_review($plan);
920             $this->fail('The plan cannot be sent for review at this stage.');
921         } catch (coding_exception $e) {
922             $this->assertRegExp('/The plan cannot be sent for review at this stage./', $e->getMessage());
923         }
925         // Can not send for review when not draft.
926         $this->setUser($user);
927         $plan->set_status(plan::STATUS_ACTIVE);
928         try {
929             api::plan_request_review($plan);
930             $this->fail('The plan cannot be sent for review at this stage.');
931         } catch (coding_exception $e) {
932             $this->assertRegExp('/The plan cannot be sent for review at this stage./', $e->getMessage());
933         }
935         // Can not send for review when not draft.
936         $this->setUser($user);
937         $plan->set_status(plan::STATUS_IN_REVIEW);
938         try {
939             api::plan_request_review($plan);
940             $this->fail('The plan cannot be sent for review at this stage.');
941         } catch (coding_exception $e) {
942             $this->assertRegExp('/The plan cannot be sent for review at this stage./', $e->getMessage());
943         }
945         // Can not send for review when not draft.
946         $this->setUser($user);
947         $plan->set_status(plan::STATUS_COMPLETE);
948         try {
949             api::plan_request_review($plan);
950             $this->fail('The plan cannot be sent for review at this stage.');
951         } catch (coding_exception $e) {
952             $this->assertRegExp('/The plan cannot be sent for review at this stage./', $e->getMessage());
953         }
955         // Sending for review as a reviewer.
956         $this->setUser($reviewer);
957         $plan->set_status(plan::STATUS_DRAFT);
958         try {
959             api::plan_request_review($plan);
960             $this->fail('The user can not request a review.');
961         } catch (required_capability_exception $e) {
962             $this->assertEquals('nopermissions', $e->errorcode);
963         }
965         // Sending for review.
966         $this->setUser($user);
967         api::plan_request_review($plan);
968         $plan->read();
969         $this->assertEquals(plan::STATUS_WAITING_FOR_REVIEW, $plan->get_status());
971         // Sending for review by ID.
972         $plan->set_status(plan::STATUS_DRAFT);
973         $plan->update();
974         api::plan_request_review($plan->get_id());
975         $plan->read();
976         $this->assertEquals(plan::STATUS_WAITING_FOR_REVIEW, $plan->get_status());
977     }
979     /**
980      * Testing cancelling the review request.
981      */
982     public function test_plan_cancel_review_request() {
983         $data = $this->setup_workflow_data();
984         $dg = $data['dg'];
985         $lpg = $data['lpg'];
986         $user = $data['user'];
987         $reviewer = $data['reviewer'];
988         $otheruser = $data['otheruser'];
989         $plan = $data['plan'];
990         $tplplan = $data['tplplan'];
992         // Set waiting for review.
993         $tplplan->set_status(plan::STATUS_WAITING_FOR_REVIEW);
994         $tplplan->update();
995         $plan->set_status(plan::STATUS_WAITING_FOR_REVIEW);
996         $plan->update();
998         // Foreign user cannot do anything.
999         $this->setUser($otheruser);
1000         try {
1001             api::plan_cancel_review_request($plan);
1002             $this->fail('The user can not read the plan.');
1003         } catch (required_capability_exception $e) {
1004             $this->assertEquals('nopermissions', $e->errorcode);
1005         }
1007         // Can not change a plan based on a template.
1008         $this->setUser($user);
1009         try {
1010             api::plan_cancel_review_request($tplplan);
1011             $this->fail('The plan is based on a template.');
1012         } catch (coding_exception $e) {
1013             $this->assertRegExp('/Template plans cannot be reviewed./', $e->getMessage());
1014         }
1016         // Can not cancel review request when not waiting for review.
1017         $this->setUser($user);
1018         $plan->set_status(plan::STATUS_DRAFT);
1019         try {
1020             api::plan_cancel_review_request($plan);
1021             $this->fail('The plan cannot be sent for review at this stage.');
1022         } catch (coding_exception $e) {
1023             $this->assertRegExp('/The plan review cannot be cancelled at this stage./', $e->getMessage());
1024         }
1026         // Can not cancel review request when not waiting for review.
1027         $this->setUser($user);
1028         $plan->set_status(plan::STATUS_IN_REVIEW);
1029         try {
1030             api::plan_cancel_review_request($plan);
1031             $this->fail('The plan review cannot be cancelled at this stage.');
1032         } catch (coding_exception $e) {
1033             $this->assertRegExp('/The plan review cannot be cancelled at this stage./', $e->getMessage());
1034         }
1036         // Can not cancel review request when not waiting for review.
1037         $this->setUser($user);
1038         $plan->set_status(plan::STATUS_ACTIVE);
1039         try {
1040             api::plan_cancel_review_request($plan);
1041             $this->fail('The plan review cannot be cancelled at this stage.');
1042         } catch (coding_exception $e) {
1043             $this->assertRegExp('/The plan review cannot be cancelled at this stage./', $e->getMessage());
1044         }
1046         // Can not cancel review request when not waiting for review.
1047         $this->setUser($user);
1048         $plan->set_status(plan::STATUS_COMPLETE);
1049         try {
1050             api::plan_cancel_review_request($plan);
1051             $this->fail('The plan review cannot be cancelled at this stage.');
1052         } catch (coding_exception $e) {
1053             $this->assertRegExp('/The plan review cannot be cancelled at this stage./', $e->getMessage());
1054         }
1056         // Cancelling as a reviewer.
1057         $this->setUser($reviewer);
1058         $plan->set_status(plan::STATUS_WAITING_FOR_REVIEW);
1059         try {
1060             api::plan_cancel_review_request($plan);
1061             $this->fail('The user can not cancel a review request.');
1062         } catch (required_capability_exception $e) {
1063             $this->assertEquals('nopermissions', $e->errorcode);
1064         }
1066         // Cancelling review request.
1067         $this->setUser($user);
1068         api::plan_cancel_review_request($plan);
1069         $plan->read();
1070         $this->assertEquals(plan::STATUS_DRAFT, $plan->get_status());
1072         // Cancelling review request by ID.
1073         $plan->set_status(plan::STATUS_WAITING_FOR_REVIEW);
1074         $plan->update();
1075         api::plan_cancel_review_request($plan->get_id());
1076         $plan->read();
1077         $this->assertEquals(plan::STATUS_DRAFT, $plan->get_status());
1078     }
1080     /**
1081      * Testing starting the review.
1082      */
1083     public function test_plan_start_review() {
1084         $data = $this->setup_workflow_data();
1085         $dg = $data['dg'];
1086         $lpg = $data['lpg'];
1087         $user = $data['user'];
1088         $reviewer = $data['reviewer'];
1089         $otheruser = $data['otheruser'];
1090         $plan = $data['plan'];
1091         $tplplan = $data['tplplan'];
1093         // Set waiting for review.
1094         $tplplan->set_status(plan::STATUS_WAITING_FOR_REVIEW);
1095         $tplplan->update();
1096         $plan->set_status(plan::STATUS_WAITING_FOR_REVIEW);
1097         $plan->update();
1099         // Foreign user cannot do anything.
1100         $this->setUser($otheruser);
1101         try {
1102             api::plan_start_review($plan);
1103             $this->fail('The user can not read the plan.');
1104         } catch (required_capability_exception $e) {
1105             $this->assertEquals('nopermissions', $e->errorcode);
1106         }
1108         // Can not change a plan based on a template.
1109         $this->setUser($reviewer);
1110         try {
1111             api::plan_start_review($tplplan);
1112             $this->fail('The plan is based on a template.');
1113         } catch (coding_exception $e) {
1114             $this->assertRegExp('/Template plans cannot be reviewed./', $e->getMessage());
1115         }
1117         // Can not start a review when not waiting for review.
1118         $this->setUser($reviewer);
1119         $plan->set_status(plan::STATUS_DRAFT);
1120         try {
1121             api::plan_start_review($plan);
1122             $this->fail('The plan review cannot be started at this stage.');
1123         } catch (coding_exception $e) {
1124             $this->assertRegExp('/The plan review cannot be started at this stage./', $e->getMessage());
1125         }
1127         // Can not start a review when not waiting for review.
1128         $this->setUser($reviewer);
1129         $plan->set_status(plan::STATUS_IN_REVIEW);
1130         try {
1131             api::plan_start_review($plan);
1132             $this->fail('The plan review cannot be started at this stage.');
1133         } catch (coding_exception $e) {
1134             $this->assertRegExp('/The plan review cannot be started at this stage./', $e->getMessage());
1135         }
1137         // Can not start a review when not waiting for review.
1138         $this->setUser($reviewer);
1139         $plan->set_status(plan::STATUS_ACTIVE);
1140         try {
1141             api::plan_start_review($plan);
1142             $this->fail('The plan review cannot be started at this stage.');
1143         } catch (coding_exception $e) {
1144             $this->assertRegExp('/The plan review cannot be started at this stage./', $e->getMessage());
1145         }
1147         // Can not start a review when not waiting for review.
1148         $this->setUser($reviewer);
1149         $plan->set_status(plan::STATUS_COMPLETE);
1150         try {
1151             api::plan_start_review($plan);
1152             $this->fail('The plan review cannot be started at this stage.');
1153         } catch (coding_exception $e) {
1154             $this->assertRegExp('/The plan review cannot be started at this stage./', $e->getMessage());
1155         }
1157         // Starting as the owner.
1158         $this->setUser($user);
1159         $plan->set_status(plan::STATUS_WAITING_FOR_REVIEW);
1160         try {
1161             api::plan_start_review($plan);
1162             $this->fail('The user can not start a review.');
1163         } catch (required_capability_exception $e) {
1164             $this->assertEquals('nopermissions', $e->errorcode);
1165         }
1167         // Starting review.
1168         $this->setUser($reviewer);
1169         api::plan_start_review($plan);
1170         $plan->read();
1171         $this->assertEquals(plan::STATUS_IN_REVIEW, $plan->get_status());
1172         $this->assertEquals($reviewer->id, $plan->get_reviewerid());
1174         // Starting review by ID.
1175         $plan->set_status(plan::STATUS_WAITING_FOR_REVIEW);
1176         $plan->set_reviewerid(null);
1177         $plan->update();
1178         api::plan_start_review($plan->get_id());
1179         $plan->read();
1180         $this->assertEquals(plan::STATUS_IN_REVIEW, $plan->get_status());
1181         $this->assertEquals($reviewer->id, $plan->get_reviewerid());
1182     }
1184     /**
1185      * Testing stopping the review.
1186      */
1187     public function test_plan_stop_review() {
1188         $data = $this->setup_workflow_data();
1189         $dg = $data['dg'];
1190         $lpg = $data['lpg'];
1191         $user = $data['user'];
1192         $reviewer = $data['reviewer'];
1193         $otheruser = $data['otheruser'];
1194         $plan = $data['plan'];
1195         $tplplan = $data['tplplan'];
1197         // Set waiting for review.
1198         $tplplan->set_status(plan::STATUS_IN_REVIEW);
1199         $tplplan->update();
1200         $plan->set_status(plan::STATUS_IN_REVIEW);
1201         $plan->update();
1203         // Foreign user cannot do anything.
1204         $this->setUser($otheruser);
1205         try {
1206             api::plan_stop_review($plan);
1207             $this->fail('The user can not read the plan.');
1208         } catch (required_capability_exception $e) {
1209             $this->assertEquals('nopermissions', $e->errorcode);
1210         }
1212         // Can not change a plan based on a template.
1213         $this->setUser($reviewer);
1214         try {
1215             api::plan_stop_review($tplplan);
1216             $this->fail('The plan is based on a template.');
1217         } catch (coding_exception $e) {
1218             $this->assertRegExp('/Template plans cannot be reviewed./', $e->getMessage());
1219         }
1221         // Can not stop a review whe not in review.
1222         $this->setUser($reviewer);
1223         $plan->set_status(plan::STATUS_DRAFT);
1224         try {
1225             api::plan_stop_review($plan);
1226             $this->fail('The plan review cannot be stopped at this stage.');
1227         } catch (coding_exception $e) {
1228             $this->assertRegExp('/The plan review cannot be stopped at this stage./', $e->getMessage());
1229         }
1231         // Can not stop a review whe not in review.
1232         $this->setUser($reviewer);
1233         $plan->set_status(plan::STATUS_WAITING_FOR_REVIEW);
1234         try {
1235             api::plan_stop_review($plan);
1236             $this->fail('The plan review cannot be stopped at this stage.');
1237         } catch (coding_exception $e) {
1238             $this->assertRegExp('/The plan review cannot be stopped at this stage./', $e->getMessage());
1239         }
1241         // Can not stop a review whe not in review.
1242         $this->setUser($reviewer);
1243         $plan->set_status(plan::STATUS_ACTIVE);
1244         try {
1245             api::plan_stop_review($plan);
1246             $this->fail('The plan review cannot be stopped at this stage.');
1247         } catch (coding_exception $e) {
1248             $this->assertRegExp('/The plan review cannot be stopped at this stage./', $e->getMessage());
1249         }
1251         // Can not stop a review whe not in review.
1252         $this->setUser($reviewer);
1253         $plan->set_status(plan::STATUS_COMPLETE);
1254         try {
1255             api::plan_stop_review($plan);
1256             $this->fail('The plan review cannot be stopped at this stage.');
1257         } catch (coding_exception $e) {
1258             $this->assertRegExp('/The plan review cannot be stopped at this stage./', $e->getMessage());
1259         }
1261         // Stopping as the owner.
1262         $this->setUser($user);
1263         $plan->set_status(plan::STATUS_IN_REVIEW);
1264         try {
1265             api::plan_stop_review($plan);
1266             $this->fail('The user can not stop a review.');
1267         } catch (required_capability_exception $e) {
1268             $this->assertEquals('nopermissions', $e->errorcode);
1269         }
1271         // Stopping review.
1272         $this->setUser($reviewer);
1273         api::plan_stop_review($plan);
1274         $plan->read();
1275         $this->assertEquals(plan::STATUS_DRAFT, $plan->get_status());
1277         // Stopping review by ID.
1278         $plan->set_status(plan::STATUS_IN_REVIEW);
1279         $plan->update();
1280         api::plan_stop_review($plan->get_id());
1281         $plan->read();
1282         $this->assertEquals(plan::STATUS_DRAFT, $plan->get_status());
1283     }
1285     /**
1286      * Testing approving the plan.
1287      */
1288     public function test_approve_plan() {
1289         $data = $this->setup_workflow_data();
1290         $dg = $data['dg'];
1291         $lpg = $data['lpg'];
1292         $user = $data['user'];
1293         $reviewer = $data['reviewer'];
1294         $otheruser = $data['otheruser'];
1295         $plan = $data['plan'];
1296         $tplplan = $data['tplplan'];
1298         // Set waiting for review.
1299         $tplplan->set_status(plan::STATUS_IN_REVIEW);
1300         $tplplan->update();
1301         $plan->set_status(plan::STATUS_IN_REVIEW);
1302         $plan->update();
1304         // Foreign user cannot do anything.
1305         $this->setUser($otheruser);
1306         try {
1307             api::approve_plan($plan);
1308             $this->fail('The user can not read the plan.');
1309         } catch (required_capability_exception $e) {
1310             $this->assertEquals('nopermissions', $e->errorcode);
1311         }
1313         // Can not change a plan based on a template.
1314         $this->setUser($reviewer);
1315         try {
1316             api::approve_plan($tplplan);
1317             $this->fail('The plan is based on a template.');
1318         } catch (coding_exception $e) {
1319             $this->assertRegExp('/Template plans are already approved./', $e->getMessage());
1320         }
1322         // Can not approve a plan already approved.
1323         $this->setUser($reviewer);
1324         $plan->set_status(plan::STATUS_ACTIVE);
1325         try {
1326             api::approve_plan($plan);
1327             $this->fail('The plan cannot be approved at this stage.');
1328         } catch (coding_exception $e) {
1329             $this->assertRegExp('/The plan cannot be approved at this stage./', $e->getMessage());
1330         }
1332         // Can not approve a plan already approved.
1333         $this->setUser($reviewer);
1334         $plan->set_status(plan::STATUS_COMPLETE);
1335         try {
1336             api::approve_plan($plan);
1337             $this->fail('The plan cannot be approved at this stage.');
1338         } catch (coding_exception $e) {
1339             $this->assertRegExp('/The plan cannot be approved at this stage./', $e->getMessage());
1340         }
1342         // Approve as the owner.
1343         $this->setUser($user);
1344         $plan->set_status(plan::STATUS_IN_REVIEW);
1345         try {
1346             api::approve_plan($plan);
1347             $this->fail('The user can not approve the plan.');
1348         } catch (required_capability_exception $e) {
1349             $this->assertEquals('nopermissions', $e->errorcode);
1350         }
1352         // Approve plan from in review.
1353         $this->setUser($reviewer);
1354         api::approve_plan($plan);
1355         $plan->read();
1356         $this->assertEquals(plan::STATUS_ACTIVE, $plan->get_status());
1358         // Approve plan by ID.
1359         $plan->set_status(plan::STATUS_IN_REVIEW);
1360         $plan->update();
1361         api::approve_plan($plan->get_id());
1362         $plan->read();
1363         $this->assertEquals(plan::STATUS_ACTIVE, $plan->get_status());
1365         // Approve plan from draft.
1366         $plan->set_status(plan::STATUS_DRAFT);
1367         $plan->update();
1368         api::approve_plan($plan);
1369         $plan->read();
1370         $this->assertEquals(plan::STATUS_ACTIVE, $plan->get_status());
1372         // Approve plan from waiting for review.
1373         $plan->set_status(plan::STATUS_WAITING_FOR_REVIEW);
1374         $plan->update();
1375         api::approve_plan($plan);
1376         $plan->read();
1377         $this->assertEquals(plan::STATUS_ACTIVE, $plan->get_status());
1378     }
1380     /**
1381      * Testing stopping the review.
1382      */
1383     public function test_unapprove_plan() {
1384         $data = $this->setup_workflow_data();
1385         $dg = $data['dg'];
1386         $lpg = $data['lpg'];
1387         $user = $data['user'];
1388         $reviewer = $data['reviewer'];
1389         $otheruser = $data['otheruser'];
1390         $plan = $data['plan'];
1391         $tplplan = $data['tplplan'];
1393         // Set waiting for review.
1394         $tplplan->set_status(plan::STATUS_ACTIVE);
1395         $tplplan->update();
1396         $plan->set_status(plan::STATUS_ACTIVE);
1397         $plan->update();
1399         // Foreign user cannot do anything.
1400         $this->setUser($otheruser);
1401         try {
1402             api::unapprove_plan($plan);
1403             $this->fail('The user can not read the plan.');
1404         } catch (required_capability_exception $e) {
1405             $this->assertEquals('nopermissions', $e->errorcode);
1406         }
1408         // Can not change a plan based on a template.
1409         $this->setUser($reviewer);
1410         try {
1411             api::unapprove_plan($tplplan);
1412             $this->fail('The plan is based on a template.');
1413         } catch (coding_exception $e) {
1414             $this->assertRegExp('/Template plans are always approved./', $e->getMessage());
1415         }
1417         // Can not unapprove a non-draft plan.
1418         $this->setUser($reviewer);
1419         $plan->set_status(plan::STATUS_DRAFT);
1420         try {
1421             api::unapprove_plan($plan);
1422             $this->fail('The plan cannot be sent back to draft at this stage.');
1423         } catch (coding_exception $e) {
1424             $this->assertRegExp('/The plan cannot be sent back to draft at this stage./', $e->getMessage());
1425         }
1427         // Can not unapprove a non-draft plan.
1428         $this->setUser($reviewer);
1429         $plan->set_status(plan::STATUS_WAITING_FOR_REVIEW);
1430         try {
1431             api::unapprove_plan($plan);
1432             $this->fail('The plan cannot be sent back to draft at this stage.');
1433         } catch (coding_exception $e) {
1434             $this->assertRegExp('/The plan cannot be sent back to draft at this stage./', $e->getMessage());
1435         }
1437         // Can not unapprove a non-draft plan.
1438         $this->setUser($reviewer);
1439         $plan->set_status(plan::STATUS_IN_REVIEW);
1440         try {
1441             api::unapprove_plan($plan);
1442             $this->fail('The plan cannot be sent back to draft at this stage.');
1443         } catch (coding_exception $e) {
1444             $this->assertRegExp('/The plan cannot be sent back to draft at this stage./', $e->getMessage());
1445         }
1447         // Can not unapprove a non-draft plan.
1448         $this->setUser($reviewer);
1449         $plan->set_status(plan::STATUS_COMPLETE);
1450         try {
1451             api::unapprove_plan($plan);
1452             $this->fail('The plan cannot be sent back to draft at this stage.');
1453         } catch (coding_exception $e) {
1454             $this->assertRegExp('/The plan cannot be sent back to draft at this stage./', $e->getMessage());
1455         }
1457         // Unapprove as the owner.
1458         $this->setUser($user);
1459         $plan->set_status(plan::STATUS_ACTIVE);
1460         try {
1461             api::unapprove_plan($plan);
1462             $this->fail('The user can not unapprove the plan.');
1463         } catch (required_capability_exception $e) {
1464             $this->assertEquals('nopermissions', $e->errorcode);
1465         }
1467         // Unapprove plan.
1468         $this->setUser($reviewer);
1469         api::unapprove_plan($plan);
1470         $plan->read();
1471         $this->assertEquals(plan::STATUS_DRAFT, $plan->get_status());
1473         // Unapprove plan by ID.
1474         $plan->set_status(plan::STATUS_ACTIVE);
1475         $plan->update();
1476         api::unapprove_plan($plan->get_id());
1477         $plan->read();
1478         $this->assertEquals(plan::STATUS_DRAFT, $plan->get_status());
1479     }
1481     /**
1482      * Test update plan and the managing of archived user competencies.
1483      */
1484     public function test_update_plan_manage_archived_competencies() {
1485         global $DB;
1487         $this->resetAfterTest(true);
1488         $dg = $this->getDataGenerator();
1489         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1491         $syscontext = context_system::instance();
1493         // Create users and roles for the test.
1494         $user = $dg->create_user();
1495         $manageownrole = $dg->create_role(array(
1496             'name' => 'User manage own',
1497             'shortname' => 'manageown'
1498         ));
1499         assign_capability('moodle/competency:planmanageowndraft', CAP_ALLOW, $manageownrole, $syscontext->id);
1500         assign_capability('moodle/competency:planviewowndraft', CAP_ALLOW, $manageownrole, $syscontext->id);
1501         assign_capability('moodle/competency:planmanageown', CAP_ALLOW, $manageownrole, $syscontext->id);
1502         assign_capability('moodle/competency:planviewown', CAP_ALLOW, $manageownrole, $syscontext->id);
1503         $dg->role_assign($manageownrole, $user->id, $syscontext->id);
1504         $this->setUser($user);
1506         // Create a framework and assign competencies.
1507         $framework = $lpg->create_framework();
1508         $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
1509         $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
1510         $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
1512         // Create two plans and assign competencies.
1513         $plan = $lpg->create_plan(array('userid' => $user->id));
1514         $otherplan = $lpg->create_plan(array('userid' => $user->id));
1516         $lpg->create_plan_competency(array('planid' => $plan->get_id(), 'competencyid' => $c1->get_id()));
1517         $lpg->create_plan_competency(array('planid' => $plan->get_id(), 'competencyid' => $c2->get_id()));
1518         $lpg->create_plan_competency(array('planid' => $plan->get_id(), 'competencyid' => $c3->get_id()));
1519         $lpg->create_plan_competency(array('planid' => $otherplan->get_id(), 'competencyid' => $c1->get_id()));
1521         $uclist = array(
1522             $lpg->create_user_competency(array(
1523                                             'userid' => $user->id,
1524                                             'competencyid' => $c1->get_id(),
1525                                             'proficiency' => true,
1526                                             'grade' => 1
1527                                         )),
1528             $lpg->create_user_competency(array(
1529                                             'userid' => $user->id,
1530                                             'competencyid' => $c2->get_id(),
1531                                             'proficiency' => false,
1532                                             'grade' => 2
1533                                         ))
1534         );
1536         // Change status of the plan to complete.
1537         $record = $plan->to_record();
1538         $record->status = \core_competency\plan::STATUS_COMPLETE;
1540         try {
1541             $plan = api::update_plan($record);
1542             $this->fail('We cannot complete a plan using api::update_plan().');
1543         } catch (coding_exception $e) {
1544             // All good.
1545         }
1546         api::complete_plan($plan);
1548         // Check that user compretencies are now in user_competency_plan objects and still in user_competency.
1549         $this->assertEquals(2, \core_competency\user_competency::count_records());
1550         $this->assertEquals(3, \core_competency\user_competency_plan::count_records());
1552         $usercompetenciesplan = \core_competency\user_competency_plan::get_records();
1554         $this->assertEquals($uclist[0]->get_userid(), $usercompetenciesplan[0]->get_userid());
1555         $this->assertEquals($uclist[0]->get_competencyid(), $usercompetenciesplan[0]->get_competencyid());
1556         $this->assertEquals($uclist[0]->get_proficiency(), (bool) $usercompetenciesplan[0]->get_proficiency());
1557         $this->assertEquals($uclist[0]->get_grade(), $usercompetenciesplan[0]->get_grade());
1558         $this->assertEquals($plan->get_id(), $usercompetenciesplan[0]->get_planid());
1560         $this->assertEquals($uclist[1]->get_userid(), $usercompetenciesplan[1]->get_userid());
1561         $this->assertEquals($uclist[1]->get_competencyid(), $usercompetenciesplan[1]->get_competencyid());
1562         $this->assertEquals($uclist[1]->get_proficiency(), (bool) $usercompetenciesplan[1]->get_proficiency());
1563         $this->assertEquals($uclist[1]->get_grade(), $usercompetenciesplan[1]->get_grade());
1564         $this->assertEquals($plan->get_id(), $usercompetenciesplan[1]->get_planid());
1566         $this->assertEquals($user->id, $usercompetenciesplan[2]->get_userid());
1567         $this->assertEquals($c3->get_id(), $usercompetenciesplan[2]->get_competencyid());
1568         $this->assertNull($usercompetenciesplan[2]->get_proficiency());
1569         $this->assertNull($usercompetenciesplan[2]->get_grade());
1570         $this->assertEquals($plan->get_id(), $usercompetenciesplan[2]->get_planid());
1572         // Change status of the plan to active.
1573         $record = $plan->to_record();
1574         $record->status = \core_competency\plan::STATUS_ACTIVE;
1576         try {
1577             api::update_plan($record);
1578             $this->fail('Completed plan can not be edited');
1579         } catch (coding_exception $e) {
1580             // All good.
1581         }
1583         api::reopen_plan($record->id);
1584         // Check that user_competency_plan objects are deleted if the plan status is changed to another status.
1585         $this->assertEquals(2, \core_competency\user_competency::count_records());
1586         $this->assertEquals(0, \core_competency\user_competency_plan::count_records());
1587     }
1589     /**
1590      * Test completing plan does not change the order of competencies.
1591      */
1592     public function test_complete_plan_doesnot_change_order() {
1593         global $DB;
1595         $this->resetAfterTest(true);
1596         $this->setAdminUser();
1597         $dg = $this->getDataGenerator();
1598         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1600         $syscontext = context_system::instance();
1602         // Create users and roles for the test.
1603         $user = $dg->create_user();
1605         // Create a framework and assign competencies.
1606         $framework = $lpg->create_framework();
1607         $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
1608         $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
1609         $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
1611         // Create two plans and assign competencies.
1612         $plan = $lpg->create_plan(array('userid' => $user->id));
1614         $lpg->create_plan_competency(array('planid' => $plan->get_id(), 'competencyid' => $c1->get_id()));
1615         $lpg->create_plan_competency(array('planid' => $plan->get_id(), 'competencyid' => $c2->get_id()));
1616         $lpg->create_plan_competency(array('planid' => $plan->get_id(), 'competencyid' => $c3->get_id()));
1618         // Changing competencies order in plan competency.
1619         api::reorder_plan_competency($plan->get_id(), $c1->get_id(), $c3->get_id());
1621         $competencies = api::list_plan_competencies($plan);
1622         $this->assertEquals($c2->get_id(), $competencies[0]->competency->get_id());
1623         $this->assertEquals($c3->get_id(), $competencies[1]->competency->get_id());
1624         $this->assertEquals($c1->get_id(), $competencies[2]->competency->get_id());
1626         // Completing plan.
1627         api::complete_plan($plan);
1629         $competencies = api::list_plan_competencies($plan);
1631         // Completing plan does not change order.
1632         $this->assertEquals($c2->get_id(), $competencies[0]->competency->get_id());
1633         $this->assertEquals($c3->get_id(), $competencies[1]->competency->get_id());
1634         $this->assertEquals($c1->get_id(), $competencies[2]->competency->get_id());
1636         // Testing plan based on template.
1637         $template = $lpg->create_template();
1638         $framework = $lpg->create_framework();
1639         $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
1640         $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
1641         $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
1643         $lpg->create_template_competency(array(
1644             'templateid' => $template->get_id(),
1645             'competencyid' => $c1->get_id()
1646         ));
1647         $lpg->create_template_competency(array(
1648             'templateid' => $template->get_id(),
1649             'competencyid' => $c2->get_id()
1650         ));
1651         $lpg->create_template_competency(array(
1652             'templateid' => $template->get_id(),
1653             'competencyid' => $c3->get_id()
1654         ));
1655         // Reorder competencies in template.
1656         api::reorder_template_competency($template->get_id(), $c1->get_id(), $c3->get_id());
1658         // Create plan from template.
1659         $plan = api::create_plan_from_template($template->get_id(), $user->id);
1661         $competencies = api::list_plan_competencies($plan);
1663         // Completing plan does not change order.
1664         $this->assertEquals($c2->get_id(), $competencies[0]->competency->get_id());
1665         $this->assertEquals($c3->get_id(), $competencies[1]->competency->get_id());
1666         $this->assertEquals($c1->get_id(), $competencies[2]->competency->get_id());
1668         // Completing plan.
1669         api::complete_plan($plan);
1671         $competencies = api::list_plan_competencies($plan);
1673         // Completing plan does not change order.
1674         $this->assertEquals($c2->get_id(), $competencies[0]->competency->get_id());
1675         $this->assertEquals($c3->get_id(), $competencies[1]->competency->get_id());
1676         $this->assertEquals($c1->get_id(), $competencies[2]->competency->get_id());
1677     }
1679     /**
1680      * Test remove plan and the managing of archived user competencies.
1681      */
1682     public function test_delete_plan_manage_archived_competencies() {
1683         $this->resetAfterTest(true);
1684         $dg = $this->getDataGenerator();
1685         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1687         $syscontext = context_system::instance();
1689         // Create user and role for the test.
1690         $user = $dg->create_user();
1691         $managerole = $dg->create_role(array(
1692             'name' => 'User manage own',
1693             'shortname' => 'manageown'
1694         ));
1695         assign_capability('moodle/competency:planmanageowndraft', CAP_ALLOW, $managerole, $syscontext->id);
1696         assign_capability('moodle/competency:planmanageown', CAP_ALLOW, $managerole, $syscontext->id);
1697         $dg->role_assign($managerole, $user->id, $syscontext->id);
1698         $this->setUser($user);
1700         // Create a framework and assign competencies.
1701         $framework = $lpg->create_framework();
1702         $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
1703         $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
1704         $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
1706         // Create completed plan with records in user_competency.
1707         $completedplan = $lpg->create_plan(array('userid' => $user->id, 'status' => \core_competency\plan::STATUS_COMPLETE));
1709         $lpg->create_plan_competency(array('planid' => $completedplan->get_id(), 'competencyid' => $c1->get_id()));
1710         $lpg->create_plan_competency(array('planid' => $completedplan->get_id(), 'competencyid' => $c2->get_id()));
1712         $uc1 = $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c1->get_id()));
1713         $uc2 = $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c2->get_id()));
1715         $ucp1 = $lpg->create_user_competency_plan(array('userid' => $user->id, 'competencyid' => $c1->get_id(),
1716                 'planid' => $completedplan->get_id()));
1717         $ucp2 = $lpg->create_user_competency_plan(array('userid' => $user->id, 'competencyid' => $c2->get_id(),
1718                 'planid' => $completedplan->get_id()));
1720         api::delete_plan($completedplan->get_id());
1722         // Check that achived user competencies are deleted.
1723         $this->assertEquals(0, \core_competency\plan::count_records());
1724         $this->assertEquals(2, \core_competency\user_competency::count_records());
1725         $this->assertEquals(0, \core_competency\user_competency_plan::count_records());
1726     }
1728     /**
1729      * Test listing of plan competencies.
1730      */
1731     public function test_list_plan_competencies_manage_archived_competencies() {
1732         $this->resetAfterTest(true);
1733         $dg = $this->getDataGenerator();
1734         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1736         $syscontext = context_system::instance();
1738         // Create user and role for the test.
1739         $user = $dg->create_user();
1740         $viewrole = $dg->create_role(array(
1741             'name' => 'User view',
1742             'shortname' => 'view'
1743         ));
1744         assign_capability('moodle/competency:planviewdraft', CAP_ALLOW, $viewrole, $syscontext->id);
1745         assign_capability('moodle/competency:planview', CAP_ALLOW, $viewrole, $syscontext->id);
1746         $dg->role_assign($viewrole, $user->id, $syscontext->id);
1747         $this->setUser($user);
1749         // Create a framework and assign competencies.
1750         $framework = $lpg->create_framework();
1751         $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
1752         $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
1753         $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
1755         // Create draft plan with records in user_competency.
1756         $draftplan = $lpg->create_plan(array('userid' => $user->id));
1758         $lpg->create_plan_competency(array('planid' => $draftplan->get_id(), 'competencyid' => $c1->get_id()));
1759         $lpg->create_plan_competency(array('planid' => $draftplan->get_id(), 'competencyid' => $c2->get_id()));
1760         $lpg->create_plan_competency(array('planid' => $draftplan->get_id(), 'competencyid' => $c3->get_id()));
1762         $uc1 = $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c1->get_id()));
1763         $uc2 = $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c2->get_id()));
1765         // Check that user_competency objects are returned when plan status is not complete.
1766         $plancompetencies = api::list_plan_competencies($draftplan);
1768         $this->assertCount(3, $plancompetencies);
1769         $this->assertInstanceOf('\core_competency\user_competency', $plancompetencies[0]->usercompetency);
1770         $this->assertEquals($uc1->get_id(), $plancompetencies[0]->usercompetency->get_id());
1771         $this->assertNull($plancompetencies[0]->usercompetencyplan);
1773         $this->assertInstanceOf('\core_competency\user_competency', $plancompetencies[1]->usercompetency);
1774         $this->assertEquals($uc2->get_id(), $plancompetencies[1]->usercompetency->get_id());
1775         $this->assertNull($plancompetencies[1]->usercompetencyplan);
1777         $this->assertInstanceOf('\core_competency\user_competency', $plancompetencies[2]->usercompetency);
1778         $this->assertEquals(0, $plancompetencies[2]->usercompetency->get_id());
1779         $this->assertNull($plancompetencies[2]->usercompetencyplan);
1781         // Create completed plan with records in user_competency_plan.
1782         $completedplan = $lpg->create_plan(array('userid' => $user->id, 'status' => \core_competency\plan::STATUS_COMPLETE));
1784         $pc1 = $lpg->create_plan_competency(array('planid' => $completedplan->get_id(), 'competencyid' => $c1->get_id()));
1785         $pc2 = $lpg->create_plan_competency(array('planid' => $completedplan->get_id(), 'competencyid' => $c2->get_id()));
1786         $pc3 = $lpg->create_plan_competency(array('planid' => $completedplan->get_id(), 'competencyid' => $c3->get_id()));
1788         $ucp1 = $lpg->create_user_competency_plan(array('userid' => $user->id, 'competencyid' => $c1->get_id(),
1789                 'planid' => $completedplan->get_id()));
1790         $ucp2 = $lpg->create_user_competency_plan(array('userid' => $user->id, 'competencyid' => $c2->get_id(),
1791                 'planid' => $completedplan->get_id()));
1792         $ucp3 = $lpg->create_user_competency_plan(array('userid' => $user->id, 'competencyid' => $c3->get_id(),
1793                 'planid' => $completedplan->get_id()));
1795         // Check that user_competency_plan objects are returned when plan status is complete.
1796         $plancompetencies = api::list_plan_competencies($completedplan);
1798         $this->assertCount(3, $plancompetencies);
1799         $this->assertInstanceOf('\core_competency\user_competency_plan', $plancompetencies[0]->usercompetencyplan);
1800         $this->assertEquals($ucp1->get_id(), $plancompetencies[0]->usercompetencyplan->get_id());
1801         $this->assertNull($plancompetencies[0]->usercompetency);
1802         $this->assertInstanceOf('\core_competency\user_competency_plan', $plancompetencies[1]->usercompetencyplan);
1803         $this->assertEquals($ucp2->get_id(), $plancompetencies[1]->usercompetencyplan->get_id());
1804         $this->assertNull($plancompetencies[1]->usercompetency);
1805         $this->assertInstanceOf('\core_competency\user_competency_plan', $plancompetencies[2]->usercompetencyplan);
1806         $this->assertEquals($ucp3->get_id(), $plancompetencies[2]->usercompetencyplan->get_id());
1807         $this->assertNull($plancompetencies[2]->usercompetency);
1808     }
1810     public function test_create_template_cohort() {
1811         $this->resetAfterTest(true);
1812         $this->setAdminUser();
1814         $dg = $this->getDataGenerator();
1815         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1817         $c1 = $dg->create_cohort();
1818         $c2 = $dg->create_cohort();
1819         $t1 = $lpg->create_template();
1820         $t2 = $lpg->create_template();
1822         $this->assertEquals(0, \core_competency\template_cohort::count_records());
1824         // Create two relations with mixed parameters.
1825         $result = api::create_template_cohort($t1->get_id(), $c1->id);
1826         $result = api::create_template_cohort($t1, $c2);
1828         $this->assertEquals(2, \core_competency\template_cohort::count_records());
1829         $this->assertInstanceOf('core_competency\template_cohort', $result);
1830         $this->assertEquals($c2->id, $result->get_cohortid());
1831         $this->assertEquals($t1->get_id(), $result->get_templateid());
1832         $this->assertEquals(2, \core_competency\template_cohort::count_records_select('templateid = :id',
1833             array('id' => $t1->get_id())));
1834         $this->assertEquals(0, \core_competency\template_cohort::count_records_select('templateid = :id',
1835             array('id' => $t2->get_id())));
1836     }
1838     public function test_create_template_cohort_permissions() {
1839         $this->resetAfterTest(true);
1841         $dg = $this->getDataGenerator();
1842         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1843         $cat = $dg->create_category();
1844         $catcontext = context_coursecat::instance($cat->id);
1845         $syscontext = context_system::instance();
1847         $user = $dg->create_user();
1848         $role = $dg->create_role();
1849         assign_capability('moodle/competency:templatemanage', CAP_ALLOW, $role, $syscontext->id, true);
1850         $dg->role_assign($role, $user->id, $syscontext->id);
1852         $cohortrole = $dg->create_role();
1853         assign_capability('moodle/cohort:view', CAP_ALLOW, $cohortrole, $syscontext->id, true);
1855         accesslib_clear_all_caches_for_unit_testing();
1857         $c1 = $dg->create_cohort();
1858         $c2 = $dg->create_cohort(array('visible' => 0, 'contextid' => $catcontext->id));
1859         $t1 = $lpg->create_template();
1861         $this->assertEquals(0, \core_competency\template_cohort::count_records());
1863         $this->setUser($user);
1864         $result = api::create_template_cohort($t1, $c1);
1865         $this->assertInstanceOf('core_competency\\template_cohort', $result);
1867         try {
1868             $result = api::create_template_cohort($t1, $c2);
1869             $this->fail('Permission required.');
1870         } catch (required_capability_exception $e) {
1871             // That's what should happen.
1872         }
1874         // Try again with the right permissions.
1875         $dg->role_assign($cohortrole, $user->id, $catcontext->id);
1876         accesslib_clear_all_caches_for_unit_testing();
1878         $result = api::create_template_cohort($t1, $c2);
1879         $this->assertInstanceOf('core_competency\\template_cohort', $result);
1880     }
1882     public function test_delete_template() {
1883         $this->resetAfterTest(true);
1884         $this->setAdminUser();
1886         $dg = $this->getDataGenerator();
1887         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1889         $c1 = $dg->create_cohort();
1890         $c2 = $dg->create_cohort();
1891         $template = $lpg->create_template();
1892         $id = $template->get_id();
1894         // Create 2 template cohorts.
1895         $tc1 = $lpg->create_template_cohort(array('templateid' => $template->get_id(), 'cohortid' => $c1->id));
1896         $tc1 = $lpg->create_template_cohort(array('templateid' => $template->get_id(), 'cohortid' => $c2->id));
1898         // Check pre-test.
1899         $this->assertTrue(\core_competency\template::record_exists($id));
1900         $this->assertEquals(2, \core_competency\template_cohort::count_records(array('templateid' => $id)));
1902         $result = api::delete_template($template->get_id());
1903         $this->assertTrue($result);
1905         // Check that the template deos not exist anymore.
1906         $this->assertFalse(\core_competency\template::record_exists($id));
1908         // Test if associated cohorts are also deleted.
1909         $this->assertEquals(0, \core_competency\template_cohort::count_records(array('templateid' => $id)));
1910     }
1912     public function test_delete_template_cohort() {
1913         $this->resetAfterTest(true);
1914         $this->setAdminUser();
1916         $dg = $this->getDataGenerator();
1917         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1919         $c1 = $dg->create_cohort();
1920         $c2 = $dg->create_cohort();
1921         $t1 = $lpg->create_template();
1922         $t2 = $lpg->create_template();
1923         $tc1 = $lpg->create_template_cohort(array('templateid' => $t1->get_id(), 'cohortid' => $c1->id));
1924         $tc1 = $lpg->create_template_cohort(array('templateid' => $t2->get_id(), 'cohortid' => $c2->id));
1926         $this->assertEquals(2, \core_competency\template_cohort::count_records());
1927         $this->assertEquals(1, \core_competency\template_cohort::count_records_select('templateid = :id',
1928             array('id' => $t1->get_id())));
1929         $this->assertEquals(1, \core_competency\template_cohort::count_records_select('templateid = :id',
1930             array('id' => $t2->get_id())));
1932         // Delete existing.
1933         $result = api::delete_template_cohort($t1->get_id(), $c1->id);
1934         $this->assertTrue($result);
1935         $this->assertEquals(1, \core_competency\template_cohort::count_records());
1936         $this->assertEquals(0, \core_competency\template_cohort::count_records_select('templateid = :id',
1937             array('id' => $t1->get_id())));
1938         $this->assertEquals(1, \core_competency\template_cohort::count_records_select('templateid = :id',
1939             array('id' => $t2->get_id())));
1941         // Delete non-existant.
1942         $result = api::delete_template_cohort($t1->get_id(), $c1->id);
1943         $this->assertTrue($result);
1944         $this->assertEquals(1, \core_competency\template_cohort::count_records());
1945         $this->assertEquals(0, \core_competency\template_cohort::count_records_select('templateid = :id',
1946             array('id' => $t1->get_id())));
1947         $this->assertEquals(1, \core_competency\template_cohort::count_records_select('templateid = :id',
1948             array('id' => $t2->get_id())));
1949     }
1951     public function test_add_evidence_log() {
1952         $this->resetAfterTest(true);
1953         $dg = $this->getDataGenerator();
1954         $lpg = $dg->get_plugin_generator('core_competency');
1956         $u1 = $dg->create_user();
1957         $u1ctx = context_user::instance($u1->id);
1958         $f1 = $lpg->create_framework();
1959         $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
1960         $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
1962         // Creating a standard evidence with minimal information.
1963         $evidence = api::add_evidence($u1->id, $c1->get_id(), $u1ctx->id, \core_competency\evidence::ACTION_LOG,
1964             'invaliddata', 'error');
1965         $evidence->read();
1966         $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get_id()));
1967         $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get_status());
1968         $this->assertSame(null, $uc->get_grade());
1969         $this->assertSame(null, $uc->get_proficiency());
1970         $this->assertEquals($uc->get_id(), $evidence->get_usercompetencyid());
1971         $this->assertEquals($u1ctx->id, $evidence->get_contextid());
1972         $this->assertEquals(\core_competency\evidence::ACTION_LOG, $evidence->get_action());
1973         $this->assertEquals('invaliddata', $evidence->get_descidentifier());
1974         $this->assertEquals('error', $evidence->get_desccomponent());
1975         $this->assertSame(null, $evidence->get_desca());
1976         $this->assertSame(null, $evidence->get_url());
1977         $this->assertSame(null, $evidence->get_grade());
1978         $this->assertSame(null, $evidence->get_actionuserid());
1980         // Creating a standard evidence with more information.
1981         $evidence = api::add_evidence($u1->id, $c1->get_id(), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata',
1982             'error', '$a', false, 'http://moodle.org', null, 2, 'The evidence of prior learning were reviewed.');
1983         $evidence->read();
1984         $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get_id()));
1985         $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get_status());
1986         $this->assertSame(null, $uc->get_grade());
1987         $this->assertSame(null, $uc->get_proficiency());
1988         $this->assertEquals($uc->get_id(), $evidence->get_usercompetencyid());
1989         $this->assertEquals($u1ctx->id, $evidence->get_contextid());
1990         $this->assertEquals(\core_competency\evidence::ACTION_LOG, $evidence->get_action());
1991         $this->assertEquals('invaliddata', $evidence->get_descidentifier());
1992         $this->assertEquals('error', $evidence->get_desccomponent());
1993         $this->assertEquals('$a', $evidence->get_desca());
1994         $this->assertEquals('http://moodle.org', $evidence->get_url());
1995         $this->assertSame(null, $evidence->get_grade());
1996         $this->assertEquals(2, $evidence->get_actionuserid());
1997         $this->assertSame('The evidence of prior learning were reviewed.', $evidence->get_note());
1999         // Creating a standard evidence and send for review.
2000         $evidence = api::add_evidence($u1->id, $c2->get_id(), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata',
2001             'error', null, true);
2002         $evidence->read();
2003         $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2->get_id()));
2004         $this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc->get_status());
2006         // Trying to pass a grade should fail.
2007         try {
2008             $evidence = api::add_evidence($u1->id, $c1->get_id(), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata',
2009                 'error', null, false, null, 1);
2010             $this->fail('A grade can not be set');
2011         } catch (coding_exception $e) {
2012             $this->assertRegExp('/grade MUST NOT be set/', $e->getMessage());
2013         }
2014     }
2016     public function test_add_evidence_complete() {
2017         $this->resetAfterTest(true);
2018         $dg = $this->getDataGenerator();
2019         $lpg = $dg->get_plugin_generator('core_competency');
2021         $u1 = $dg->create_user();
2022         $u1ctx = context_user::instance($u1->id);
2023         $scale = $dg->create_scale(array('scale' => 'A,B,C,D'));
2024         $scaleconfig = array(array('scaleid' => $scale->id));
2025         $scaleconfig[] = array('name' => 'B', 'id' => 2, 'scaledefault' => 1, 'proficient' => 0);
2026         $scaleconfig[] = array('name' => 'C', 'id' => 3, 'scaledefault' => 0, 'proficient' => 1);
2027         $scaleconfig[] = array('name' => 'D', 'id' => 4, 'scaledefault' => 0, 'proficient' => 1);
2028         $c2scaleconfig = array(array('scaleid' => $scale->id));
2029         $c2scaleconfig[] = array('name' => 'B', 'id' => 2, 'scaledefault' => 0, 'proficient' => 1);
2030         $c2scaleconfig[] = array('name' => 'C', 'id' => 3, 'scaledefault' => 0, 'proficient' => 0);
2031         $c2scaleconfig[] = array('name' => 'D', 'id' => 4, 'scaledefault' => 1, 'proficient' => 1);
2032         $f1 = $lpg->create_framework(array('scaleid' => $scale->id, 'scaleconfiguration' => $scaleconfig));
2033         $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
2034         $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'scaleid' => $scale->id,
2035             'scaleconfiguration' => $c2scaleconfig));
2036         $c3 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
2038         // Creating an evidence with minimal information.
2039         $evidence = api::add_evidence($u1->id, $c1->get_id(), $u1ctx->id, \core_competency\evidence::ACTION_COMPLETE, 'invaliddata',
2040             'error');
2041         $evidence->read();
2042         $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get_id()));
2043         $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get_status());
2044         $this->assertEquals(2, $uc->get_grade());    // The grade has been set automatically to the framework default.
2045         $this->assertEquals(0, $uc->get_proficiency());
2046         $this->assertEquals($uc->get_id(), $evidence->get_usercompetencyid());
2047         $this->assertEquals($u1ctx->id, $evidence->get_contextid());
2048         $this->assertEquals(\core_competency\evidence::ACTION_COMPLETE, $evidence->get_action());
2049         $this->assertEquals('invaliddata', $evidence->get_descidentifier());
2050         $this->assertEquals('error', $evidence->get_desccomponent());
2051         $this->assertSame(null, $evidence->get_desca());
2052         $this->assertSame(null, $evidence->get_url());
2053         $this->assertEquals(2, $evidence->get_grade());
2054         $this->assertSame(null, $evidence->get_actionuserid());
2056         // Creating an evidence complete on competency with custom scale.
2057         $evidence = api::add_evidence($u1->id, $c2->get_id(), $u1ctx->id, \core_competency\evidence::ACTION_COMPLETE, 'invaliddata',
2058             'error');
2059         $evidence->read();
2060         $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2->get_id()));
2061         $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get_status());
2062         $this->assertEquals(4, $uc->get_grade());    // The grade has been set automatically to the competency default.
2063         $this->assertEquals(true, $uc->get_proficiency());
2064         $this->assertEquals($uc->get_id(), $evidence->get_usercompetencyid());
2065         $this->assertEquals($u1ctx->id, $evidence->get_contextid());
2066         $this->assertEquals(\core_competency\evidence::ACTION_COMPLETE, $evidence->get_action());
2067         $this->assertEquals('invaliddata', $evidence->get_descidentifier());
2068         $this->assertEquals('error', $evidence->get_desccomponent());
2069         $this->assertSame(null, $evidence->get_desca());
2070         $this->assertSame(null, $evidence->get_url());
2071         $this->assertEquals(4, $evidence->get_grade());
2072         $this->assertSame(null, $evidence->get_actionuserid());
2074         // Creating an evidence complete on a user competency with an existing grade.
2075         $uc = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c3->get_id(), 'grade' => 1,
2076             'proficiency' => 0));
2077         $this->assertEquals(1, $uc->get_grade());
2078         $this->assertEquals(0, $uc->get_proficiency());
2079         $evidence = api::add_evidence($u1->id, $c3->get_id(), $u1ctx->id, \core_competency\evidence::ACTION_COMPLETE, 'invaliddata',
2080             'error');
2081         $evidence->read();
2082         $uc->read();
2083         $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get_status());
2084         $this->assertEquals(1, $uc->get_grade());    // The grade has not been changed.
2085         $this->assertEquals(0, $uc->get_proficiency());
2086         $this->assertEquals($uc->get_id(), $evidence->get_usercompetencyid());
2087         $this->assertEquals($u1ctx->id, $evidence->get_contextid());
2088         $this->assertEquals(\core_competency\evidence::ACTION_COMPLETE, $evidence->get_action());
2089         $this->assertEquals('invaliddata', $evidence->get_descidentifier());
2090         $this->assertEquals('error', $evidence->get_desccomponent());
2091         $this->assertSame(null, $evidence->get_desca());
2092         $this->assertSame(null, $evidence->get_url());
2093         $this->assertEquals(2, $evidence->get_grade());     // The complete grade has been set.
2094         $this->assertSame(null, $evidence->get_actionuserid());
2096         // Creating a standard evidence and send for review.
2097         $evidence = api::add_evidence($u1->id, $c2->get_id(), $u1ctx->id, \core_competency\evidence::ACTION_COMPLETE, 'invaliddata',
2098             'error', null, true);
2099         $evidence->read();
2100         $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2->get_id()));
2101         $this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc->get_status());
2103         // Trying to pass a grade should throw an exception.
2104         try {
2105             api::add_evidence($u1->id, $c2->get_id(), $u1ctx->id, \core_competency\evidence::ACTION_COMPLETE, 'invaliddata',
2106                 'error', null, false, null, 1);
2107         } catch (coding_exception $e) {
2108             $this->assertRegExp('/grade MUST NOT be set/', $e->getMessage());
2109         }
2110     }
2112     public function test_add_evidence_override() {
2113         $this->resetAfterTest(true);
2114         $dg = $this->getDataGenerator();
2115         $lpg = $dg->get_plugin_generator('core_competency');
2117         $u1 = $dg->create_user();
2118         $u1ctx = context_user::instance($u1->id);
2119         $f1 = $lpg->create_framework();
2120         $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
2122         // Creating an evidence with minimal information.
2123         $evidence = api::add_evidence($u1->id, $c1->get_id(), $u1ctx->id, \core_competency\evidence::ACTION_OVERRIDE, 'invaliddata',
2124             'error');
2125         $evidence->read();
2126         $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get_id()));
2127         $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get_status());
2128         $this->assertSame(null, $uc->get_grade());      // We overrode with 'null'.
2129         $this->assertSame(null, $uc->get_proficiency());
2130         $this->assertEquals($uc->get_id(), $evidence->get_usercompetencyid());
2131         $this->assertEquals($u1ctx->id, $evidence->get_contextid());
2132         $this->assertEquals(\core_competency\evidence::ACTION_OVERRIDE, $evidence->get_action());
2133         $this->assertEquals('invaliddata', $evidence->get_descidentifier());
2134         $this->assertEquals('error', $evidence->get_desccomponent());
2135         $this->assertSame(null, $evidence->get_desca());
2136         $this->assertSame(null, $evidence->get_url());
2137         $this->assertSame(null, $evidence->get_grade()); // We overrode with 'null'.
2138         $this->assertSame(null, $evidence->get_actionuserid());
2140         // Creating an evidence with a grade information.
2141         $evidence = api::add_evidence($u1->id, $c1->get_id(), $u1ctx->id, \core_competency\evidence::ACTION_OVERRIDE, 'invaliddata',
2142             'error', null, false, null, 3);
2143         $evidence->read();
2144         $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get_id()));
2145         $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get_status());
2146         $this->assertEquals(3, $uc->get_grade());
2147         $this->assertEquals(true, $uc->get_proficiency());
2148         $this->assertEquals($uc->get_id(), $evidence->get_usercompetencyid());
2149         $this->assertEquals($u1ctx->id, $evidence->get_contextid());
2150         $this->assertEquals(\core_competency\evidence::ACTION_OVERRIDE, $evidence->get_action());
2151         $this->assertEquals('invaliddata', $evidence->get_descidentifier());
2152         $this->assertEquals('error', $evidence->get_desccomponent());
2153         $this->assertSame(null, $evidence->get_desca());
2154         $this->assertSame(null, $evidence->get_url());
2155         $this->assertEquals(3, $evidence->get_grade());
2156         $this->assertSame(null, $evidence->get_actionuserid());
2158         // Creating an evidence with another grade information.
2159         $evidence = api::add_evidence($u1->id, $c1->get_id(), $u1ctx->id, \core_competency\evidence::ACTION_OVERRIDE, 'invaliddata',
2160             'error', null, false, null, 1);
2161         $evidence->read();
2162         $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get_id()));
2163         $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get_status());
2164         $this->assertEquals(1, $uc->get_grade());
2165         $this->assertEquals(0, $uc->get_proficiency());
2166         $this->assertEquals($uc->get_id(), $evidence->get_usercompetencyid());
2167         $this->assertEquals($u1ctx->id, $evidence->get_contextid());
2168         $this->assertEquals(\core_competency\evidence::ACTION_OVERRIDE, $evidence->get_action());
2169         $this->assertEquals('invaliddata', $evidence->get_descidentifier());
2170         $this->assertEquals('error', $evidence->get_desccomponent());
2171         $this->assertSame(null, $evidence->get_desca());
2172         $this->assertSame(null, $evidence->get_url());
2173         $this->assertEquals(1, $evidence->get_grade());
2174         $this->assertSame(null, $evidence->get_actionuserid());
2176         // Creating reverting the grade and send for review.
2177         $evidence = api::add_evidence($u1->id, $c1->get_id(), $u1ctx->id, \core_competency\evidence::ACTION_OVERRIDE, 'invaliddata',
2178             'error', null, true);
2179         $evidence->read();
2180         $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get_id()));
2181         $this->assertSame(null, $uc->get_grade());
2182         $this->assertSame(null, $uc->get_proficiency());
2183         $this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc->get_status());
2184         $this->assertSame(null, $evidence->get_grade());
2185     }
2187     public function test_add_evidence_and_send_for_review() {
2188         $this->resetAfterTest(true);
2189         $dg = $this->getDataGenerator();
2190         $lpg = $dg->get_plugin_generator('core_competency');
2192         $u1 = $dg->create_user();
2193         $u1ctx = context_user::instance($u1->id);
2194         $f1 = $lpg->create_framework();
2195         $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
2197         // Non-existing user competencies are created up for review.
2198         $evidence = api::add_evidence($u1->id, $c1->get_id(), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata',
2199             'error', null, true);
2200         $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get_id()));
2201         $this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc->get_status());
2203         // Existing user competencies sent for review don't change.
2204         $evidence = api::add_evidence($u1->id, $c1->get_id(), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata',
2205             'error', null, true);
2206         $uc->read();
2207         $this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc->get_status());
2209         // A user competency with a status non-idle won't change.
2210         $uc->set_status(\core_competency\user_competency::STATUS_IN_REVIEW);
2211         $uc->update();
2212         $evidence = api::add_evidence($u1->id, $c1->get_id(), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata',
2213             'error', null, true);
2214         $uc->read();
2215         $this->assertEquals(\core_competency\user_competency::STATUS_IN_REVIEW, $uc->get_status());
2216     }
2218     /**
2219      * Test add evidence for existing user_competency.
2220      */
2221     public function test_add_evidence_existing_user_competency() {
2222         $this->resetAfterTest(true);
2223         $dg = $this->getDataGenerator();
2224         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
2226         $syscontext = context_system::instance();
2228         // Create users.
2229         $user = $dg->create_user();
2230         $this->setUser($user);
2232         // Create a framework and assign competencies.
2233         $framework = $lpg->create_framework();
2234         $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
2235         $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
2236         $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
2237         $uc = $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c1->get_id()));
2238         $this->assertSame(null, $uc->get_grade());
2239         $this->assertSame(null, $uc->get_proficiency());
2241         // Create an evidence and check it was created with the right usercomptencyid and information.
2242         $evidence = api::add_evidence($user->id, $c1->get_id(), $syscontext->id, \core_competency\evidence::ACTION_OVERRIDE,
2243             'invalidevidencedesc', 'core_competency', array('a' => 'b'), false, 'http://moodle.org', 1, 2);
2244         $this->assertEquals(1, \core_competency\evidence::count_records());
2246         $evidence->read();
2247         $uc->read();
2248         $this->assertEquals($uc->get_id(), $evidence->get_usercompetencyid());
2249         $this->assertEquals('invalidevidencedesc', $evidence->get_descidentifier());
2250         $this->assertEquals('core_competency', $evidence->get_desccomponent());
2251         $this->assertEquals((object) array('a' => 'b'), $evidence->get_desca());
2252         $this->assertEquals('http://moodle.org', $evidence->get_url());
2253         $this->assertEquals(\core_competency\evidence::ACTION_OVERRIDE, $evidence->get_action());
2254         $this->assertEquals(2, $evidence->get_actionuserid());
2255         $this->assertEquals(1, $evidence->get_grade());
2256         $this->assertEquals(1, $uc->get_grade());
2257         $this->assertEquals(0, $uc->get_proficiency());
2258     }
2260     /**
2261      * Test add evidence for non-existing user_competency.
2262      */
2263     public function test_add_evidence_no_existing_user_competency() {
2264         $this->resetAfterTest(true);
2265         $dg = $this->getDataGenerator();
2266         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
2268         $syscontext = context_system::instance();
2270         // Create users.
2271         $user = $dg->create_user();
2272         $this->setUser($user);
2274         // Create a framework and assign competencies.
2275         $framework = $lpg->create_framework();
2276         $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
2277         $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
2278         $this->assertEquals(0, \core_competency\user_competency::count_records());
2280         // Create an evidence without a user competency record.
2281         $evidence = api::add_evidence($user->id, $c1->get_id(), $syscontext->id, \core_competency\evidence::ACTION_OVERRIDE,
2282             'invalidevidencedesc', 'core_competency', 'Hello world!', false, 'http://moodle.org', 1, 2);
2283         $this->assertEquals(1, \core_competency\evidence::count_records());
2284         $this->assertEquals(1, \core_competency\user_competency::count_records());
2286         $uc = \core_competency\user_competency::get_record(array('userid' => $user->id, 'competencyid' => $c1->get_id()));
2287         $evidence->read();
2288         $this->assertEquals($uc->get_id(), $evidence->get_usercompetencyid());
2289         $this->assertEquals('invalidevidencedesc', $evidence->get_descidentifier());
2290         $this->assertEquals('core_competency', $evidence->get_desccomponent());
2291         $this->assertEquals('Hello world!', $evidence->get_desca());
2292         $this->assertEquals('http://moodle.org', $evidence->get_url());
2293         $this->assertEquals(\core_competency\evidence::ACTION_OVERRIDE, $evidence->get_action());
2294         $this->assertEquals(2, $evidence->get_actionuserid());
2295         $this->assertEquals(1, $evidence->get_grade());
2296         $this->assertEquals(1, $uc->get_grade());
2297         $this->assertEquals(0, $uc->get_proficiency());
2298     }
2300     public function test_add_evidence_applies_competency_rules() {
2301         $this->resetAfterTest(true);
2302         $dg = $this->getDataGenerator();
2303         $lpg = $dg->get_plugin_generator('core_competency');
2304         $syscontext = context_system::instance();
2305         $ctxid = $syscontext->id;
2307         $u1 = $dg->create_user();
2309         // Setting up the framework.
2310         $f1 = $lpg->create_framework();
2311         $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
2312         $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c1->get_id()));
2313         $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c1->get_id()));
2314         $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
2315         $c2a = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c2->get_id()));
2316         $c3 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
2317         $c3a = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c3->get_id()));
2318         $c4 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
2319         $c4a = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c4->get_id()));
2320         $c5 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
2322         // Setting up the rules.
2323         $c1->set_ruletype('core_competency\\competency_rule_all');
2324         $c1->set_ruleoutcome(\core_competency\competency::OUTCOME_COMPLETE);
2325         $c1->update();
2326         $c2->set_ruletype('core_competency\\competency_rule_all');
2327         $c2->set_ruleoutcome(\core_competency\competency::OUTCOME_RECOMMEND);
2328         $c2->update();
2329         $c3->set_ruletype('core_competency\\competency_rule_all');
2330         $c3->set_ruleoutcome(\core_competency\competency::OUTCOME_EVIDENCE);
2331         $c3->update();
2332         $c4->set_ruletype('core_competency\\competency_rule_all');
2333         $c4->set_ruleoutcome(\core_competency\competency::OUTCOME_NONE);
2334         $c4->update();
2336         // Confirm the current data.
2337         $this->assertEquals(0, user_competency::count_records());
2338         $this->assertEquals(0, evidence::count_records());
2340         // Let's do this!
2341         // First let's confirm that evidence not marking a completion have no impact.
2342         api::add_evidence($u1->id, $c1a, $ctxid, evidence::ACTION_LOG, 'commentincontext', 'core');
2343         $uc1a = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1a->get_id()));
2344         $this->assertSame(null, $uc1a->get_proficiency());
2345         $this->assertFalse(user_competency::record_exists_select('userid = ? AND competencyid = ?', array($u1->id, $c1->get_id())));
2347         // Now let's try complete a competency but the rule won't match (not all children are complete).
2348         // The parent (the thing with the rule) will be created but won't have any evidence attached, and not
2349         // not be marked as completed.
2350         api::add_evidence($u1->id, $c1a, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');
2351         $uc1a = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1a->get_id()));
2352         $this->assertEquals(true, $uc1a->get_proficiency());
2353         $uc1 = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get_id()));
2354         $this->assertSame(null, $uc1->get_proficiency());
2355         $this->assertEquals(0, evidence::count_records(array('usercompetencyid' => $uc1->get_id())));
2357         // Now we complete the other child. That will mark the parent as complete with an evidence.
2358         api::add_evidence($u1->id, $c1b, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');
2359         $uc1b = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1b->get_id()));
2360         $this->assertEquals(true, $uc1a->get_proficiency());
2361         $uc1 = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get_id()));
2362         $this->assertEquals(true, $uc1->get_proficiency());
2363         $this->assertEquals(user_competency::STATUS_IDLE, $uc1->get_status());
2364         $this->assertEquals(1, evidence::count_records(array('usercompetencyid' => $uc1->get_id())));
2366         // Check rule recommending.
2367         api::add_evidence($u1->id, $c2a, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');
2368         $uc2a = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2a->get_id()));
2369         $this->assertEquals(true, $uc1a->get_proficiency());
2370         $uc2 = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2->get_id()));
2371         $this->assertSame(null, $uc2->get_proficiency());
2372         $this->assertEquals(user_competency::STATUS_WAITING_FOR_REVIEW, $uc2->get_status());
2373         $this->assertEquals(1, evidence::count_records(array('usercompetencyid' => $uc2->get_id())));
2375         // Check rule evidence.
2376         api::add_evidence($u1->id, $c3a, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');
2377         $uc3a = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c3a->get_id()));
2378         $this->assertEquals(true, $uc1a->get_proficiency());
2379         $uc3 = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c3->get_id()));
2380         $this->assertSame(null, $uc3->get_proficiency());
2381         $this->assertEquals(user_competency::STATUS_IDLE, $uc3->get_status());
2382         $this->assertEquals(1, evidence::count_records(array('usercompetencyid' => $uc3->get_id())));
2384         // Check rule nothing.
2385         api::add_evidence($u1->id, $c4a, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');
2386         $uc4a = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c4a->get_id()));
2387         $this->assertEquals(true, $uc1a->get_proficiency());
2388         $this->assertFalse(user_competency::record_exists_select('userid = ? AND competencyid = ?', array($u1->id, $c4->get_id())));
2390         // Check marking on something that has no parent. This just checks that nothing breaks.
2391         api::add_evidence($u1->id, $c5, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');
2392     }
2394     /**
2395      * Tests for the user_competency_course data when api::add_evidence() is invoked when
2396      * grading a user competency in the system context.
2397      */
2398     public function test_add_evidence_for_user_competency_course_grade_outside_course() {
2399         $this->resetAfterTest(true);
2400         $dg = $this->getDataGenerator();
2401         $syscontext = context_system::instance();
2403         // Create a student.
2404         $student = $dg->create_user();
2406         // Create a competency for the course.
2407         $lpg = $dg->get_plugin_generator('core_competency');
2408         $framework = $lpg->create_framework();
2409         $comp = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
2411         // Add evidence.
2412         api::add_evidence($student->id, $comp, $syscontext, evidence::ACTION_OVERRIDE,
2413             'commentincontext', 'core', null, false, null, 1);
2415         // Query for user_competency_course data.
2416         $filterparams = array(
2417             'userid' => $student->id,
2418             'competencyid' => $comp->get_id(),
2419         );
2420         $usercompcourse = \core_competency\user_competency_course::get_record($filterparams);
2421         // There should be no user_competency_course object created when grading.
2422         $this->assertFalse($usercompcourse);
2423     }
2425     /**
2426      * Tests for the user_competency_course data when api::add_evidence() is invoked when
2427      * grading a user competency in a course.
2428      */
2429     public function test_add_evidence_user_competency_course_grade_in_course() {
2430         global $USER;
2432         $this->resetAfterTest(true);
2433         $dg = $this->getDataGenerator();
2435         // Create a course.
2436         $course = $dg->create_course();
2437         $record = array('courseid' => $course->id, 'pushratingstouserplans' => false);
2438         $settings = new course_competency_settings(0, (object) $record);
2439         $settings->create();
2440         $coursecontext = context_course::instance($course->id);
2442         // Create a student and enrol into the course.
2443         $student = $dg->create_user();
2444         $studentarch = get_archetype_roles('student');
2445         $studentrole = array_shift($studentarch);
2446         $dg->role_assign($studentrole->id, $student->id, $coursecontext->id);
2447         $dg->enrol_user($student->id, $course->id, $studentrole->id);
2449         // Create a competency for the course.
2450         $lpg = $dg->get_plugin_generator('core_competency');
2451         $framework = $lpg->create_framework();
2452         // Do not push ratings from course to user plans.
2453         $comp = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
2454         $lpg->create_course_competency(array('courseid' => $course->id, 'competencyid' => $comp->get_id()));
2456         // Query for user_competency_course data.
2457         $filterparams = array(
2458             'userid' => $student->id,
2459             'competencyid' => $comp->get_id(),
2460             'courseid' => $course->id
2461         );
2463         // Add evidence that sets a grade to the course.
2464         $evidence = api::add_evidence($student->id, $comp, $coursecontext, evidence::ACTION_OVERRIDE,
2465             'commentincontext', 'core', null, false, null, 3, $USER->id);
2466         // Get user competency course record.
2467         $usercompcourse = \core_competency\user_competency_course::get_record($filterparams);
2468         // There should be a user_competency_course object when adding a grade.
2469         $this->assertNotEmpty($usercompcourse);
2470         $grade = $evidence->get_grade();
2471         $this->assertEquals($grade, $usercompcourse->get_grade());
2472         $this->assertEquals(3, $usercompcourse->get_grade());
2473         $proficiency = $comp->get_proficiency_of_grade($grade);
2474         $this->assertEquals($proficiency, $usercompcourse->get_proficiency());
2476         // Confirm that the user competency's grade/proficiency has not been affected by the grade.
2477         $usercompetencyparams = [
2478             'userid' => $student->id,
2479             'competencyid' => $comp->get_id(),
2480         ];
2481         $usercompetency = \core_competency\user_competency::get_record($usercompetencyparams);
2482         $this->assertNotEmpty($usercompetency);
2483         $this->assertNotEquals($usercompcourse->get_grade(), $usercompetency->get_grade());
2484         $this->assertNotEquals($usercompcourse->get_proficiency(), $usercompetency->get_proficiency());
2485     }
2487     public function test_observe_course_completed() {
2488         $this->resetAfterTest(true);
2489         $dg = $this->getDataGenerator();
2490         $lpg = $dg->get_plugin_generator('core_competency');
2492         // Set-up users, framework, competencies and course competencies.
2493         $course = $dg->create_course();
2494         $coursectx = context_course::instance($course->id);
2495         $u1 = $dg->create_user();
2496         $f1 = $lpg->create_framework();
2497         $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
2498         $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
2499         $c3 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
2500         $c4 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
2501         $cc1 = $lpg->create_course_competency(array('competencyid' => $c1->get_id(), 'courseid' => $course->id,
2502             'ruleoutcome' => \core_competency\course_competency::OUTCOME_NONE));
2503         $cc2 = $lpg->create_course_competency(array('competencyid' => $c2->get_id(), 'courseid' => $course->id,
2504             'ruleoutcome' => \core_competency\course_competency::OUTCOME_EVIDENCE));
2505         $cc3 = $lpg->create_course_competency(array('competencyid' => $c3->get_id(), 'courseid' => $course->id,
2506             'ruleoutcome' => \core_competency\course_competency::OUTCOME_RECOMMEND));
2507         $cc4 = $lpg->create_course_competency(array('competencyid' => $c4->get_id(), 'courseid' => $course->id,
2508             'ruleoutcome' => \core_competency\course_competency::OUTCOME_COMPLETE));
2510         $event = \core\event\course_completed::create(array(
2511             'objectid' => 1,
2512             'relateduserid' => $u1->id,
2513             'context' => $coursectx,
2514             'courseid' => $course->id,
2515             'other' => array('relateduserid' => $u1->id)
2516         ));
2517         $this->assertEquals(0, \core_competency\user_competency::count_records());
2518         $this->assertEquals(0, \core_competency\evidence::count_records());
2520         // Let's go!
2521         api::observe_course_completed($event);
2522         $this->assertEquals(3, \core_competency\user_competency::count_records());
2523         $this->assertEquals(3, \core_competency\evidence::count_records());
2525         // Outcome NONE did nothing.
2526         $this->assertFalse(\core_competency\user_competency::record_exists_select('userid = :uid AND competencyid = :cid', array(
2527             'uid' => $u1->id, 'cid' => $c1->get_id()
2528         )));
2530         // Outcome evidence.
2531         $uc2 = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2->get_id()));
2532         $ev2 = \core_competency\evidence::get_record(array('usercompetencyid' => $uc2->get_id()));
2534         $this->assertEquals(null, $uc2->get_grade());
2535         $this->assertEquals(null, $uc2->get_proficiency());
2536         $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc2->get_status());
2538         $this->assertEquals('evidence_coursecompleted', $ev2->get_descidentifier());
2539         $this->assertEquals('core_competency', $ev2->get_desccomponent());
2540         $this->assertEquals($course->shortname, $ev2->get_desca());
2541         $this->assertStringEndsWith('/report/completion/index.php?course=' . $course->id, $ev2->get_url());
2542         $this->assertEquals(null, $ev2->get_grade());
2543         $this->assertEquals($coursectx->id, $ev2->get_contextid());
2544         $this->assertEquals(\core_competency\evidence::ACTION_LOG, $ev2->get_action());
2545         $this->assertEquals(null, $ev2->get_actionuserid());
2547         // Outcome recommend.
2548         $uc3 = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c3->get_id()));
2549         $ev3 = \core_competency\evidence::get_record(array('usercompetencyid' => $uc3->get_id()));
2551         $this->assertEquals(null, $uc3->get_grade());
2552         $this->assertEquals(null, $uc3->get_proficiency());
2553         $this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc3->get_status());
2555         $this->assertEquals('evidence_coursecompleted', $ev3->get_descidentifier());
2556         $this->assertEquals('core_competency', $ev3->get_desccomponent());
2557         $this->assertEquals($course->shortname, $ev3->get_desca());
2558         $this->assertStringEndsWith('/report/completion/index.php?course=' . $course->id, $ev3->get_url());
2559         $this->assertEquals(null, $ev3->get_grade());
2560         $this->assertEquals($coursectx->id, $ev3->get_contextid());
2561         $this->assertEquals(\core_competency\evidence::ACTION_LOG, $ev3->get_action());
2562         $this->assertEquals(null, $ev3->get_actionuserid());
2564         // Outcome complete.
2565         $uc4 = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c4->get_id()));
2566         $ev4 = \core_competency\evidence::get_record(array('usercompetencyid' => $uc4->get_id()));
2568         $this->assertEquals(3, $uc4->get_grade());
2569         $this->assertEquals(1, $uc4->get_proficiency());
2570         $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc4->get_status());
2572         $this->assertEquals('evidence_coursecompleted', $ev4->get_descidentifier());
2573         $this->assertEquals('core_competency', $ev4->get_desccomponent());
2574         $this->assertEquals($course->shortname, $ev4->get_desca());
2575         $this->assertStringEndsWith('/report/completion/index.php?course=' . $course->id, $ev4->get_url());
2576         $this->assertEquals(3, $ev4->get_grade());
2577         $this->assertEquals($coursectx->id, $ev4->get_contextid());
2578         $this->assertEquals(\core_competency\evidence::ACTION_COMPLETE, $ev4->get_action());
2579         $this->assertEquals(null, $ev4->get_actionuserid());
2580     }
2582     public function test_list_evidence_in_course() {
2583         global $SITE;
2585         $this->resetAfterTest(true);
2586         $dg = $this->getDataGenerator();
2587         $lpg = $dg->get_plugin_generator('core_competency');
2588         $u1 = $dg->create_user();
2589         $course = $dg->create_course();
2590         $coursecontext = context_course::instance($course->id);
2592         $this->setAdminUser();
2593         $f = $lpg->create_framework();
2594         $c = $lpg->create_competency(array('competencyframeworkid' => $f->get_id()));
2595         $c2 = $lpg->create_competency(array('competencyframeworkid' => $f->get_id()));
2596         $cc = api::add_competency_to_course($course->id, $c->get_id());
2597         $cc2 = api::add_competency_to_course($course->id, $c2->get_id());
2599         $pagegenerator = $this->getDataGenerator()->get_plugin_generator('mod_page');
2600         $page = $pagegenerator->create_instance(array('course' => $course->id));
2602         $cm = get_coursemodule_from_instance('page', $page->id);
2603         $cmcontext = context_module::instance($cm->id);
2604         // Add the competency to the course module.
2605         $ccm = api::add_competency_to_course_module($cm, $c->get_id());
2607         // Now add the evidence to the course.
2608         $evidence1 = api::add_evidence($u1->id, $c->get_id(), $coursecontext->id, \core_competency\evidence::ACTION_LOG,
2609             'invaliddata', 'error');
2611         $result = api::list_evidence_in_course($u1->id, $course->id, $c->get_id());
2612         $this->assertEquals($result[0]->get_id(), $evidence1->get_id());
2614         // Now add the evidence to the course module.
2615         $evidence2 = api::add_evidence($u1->id, $c->get_id(), $cmcontext->id, \core_competency\evidence::ACTION_LOG,
2616             'invaliddata', 'error');
2618         $result = api::list_evidence_in_course($u1->id, $course->id, $c->get_id(), 'timecreated', 'ASC');
2619         $this->assertEquals($evidence1->get_id(), $result[0]->get_id());
2620         $this->assertEquals($evidence2->get_id(), $result[1]->get_id());
2621     }
2623     public function test_list_course_modules_using_competency() {
2624         global $SITE;
2626         $this->resetAfterTest(true);
2627         $dg = $this->getDataGenerator();
2628         $lpg = $dg->get_plugin_generator('core_competency');
2629         $u1 = $dg->create_user();
2630         $u2 = $dg->create_user();
2631         $course = $dg->create_course();
2632         $course2 = $dg->create_course();
2634         $this->setAdminUser();
2635         $f = $lpg->create_framework();
2636         $c = $lpg->create_competency(array('competencyframeworkid' => $f->get_id()));
2637         $c2 = $lpg->create_competency(array('competencyframeworkid' => $f->get_id()));
2638         $cc = api::add_competency_to_course($course->id, $c->get_id());
2639         $cc2 = api::add_competency_to_course($course->id, $c2->get_id());
2641         // First check we get an empty list when there are no links.
2642         $expected = array();
2643         $result = api::list_course_modules_using_competency($c->get_id(), $course->id);
2644         $this->assertEquals($expected, $result);
2646         $pagegenerator = $this->getDataGenerator()->get_plugin_generator('mod_page');
2647         $page = $pagegenerator->create_instance(array('course' => $course->id));
2649         $cm = get_coursemodule_from_instance('page', $page->id);
2650         // Add a link and list again.
2651         $ccm = api::add_competency_to_course_module($cm, $c->get_id());
2652         $expected = array($cm->id);
2653         $result = api::list_course_modules_using_competency($c->get_id(), $course->id);
2654         $this->assertEquals($expected, $result);
2656         // Check a different course.
2657         $expected = array();
2658         $result = api::list_course_modules_using_competency($c->get_id(), $course2->id);
2659         $this->assertEquals($expected, $result);
2661         // Remove the link and check again.
2662         $result = api::remove_competency_from_course_module($cm, $c->get_id());
2663         $expected = true;
2664         $this->assertEquals($expected, $result);
2665         $expected = array();
2666         $result = api::list_course_modules_using_competency($c->get_id(), $course->id);
2667         $this->assertEquals($expected, $result);
2669         // Now add 2 links.
2670         api::add_competency_to_course_module($cm, $c->get_id());
2671         api::add_competency_to_course_module($cm, $c2->get_id());
2672         $result = api::list_course_module_competencies_in_course_module($cm->id);
2673         $this->assertEquals($result[0]->get_competencyid(), $c->get_id());
2674         $this->assertEquals($result[1]->get_competencyid(), $c2->get_id());
2676         // Now re-order.
2677         api::reorder_course_module_competency($cm, $c->get_id(), $c2->get_id());
2678         $result = api::list_course_module_competencies_in_course_module($cm->id);
2679         $this->assertEquals($result[0]->get_competencyid(), $c2->get_id());
2680         $this->assertEquals($result[1]->get_competencyid(), $c->get_id());
2682         // And re-order again.
2683         api::reorder_course_module_competency($cm, $c->get_id(), $c2->get_id());
2684         $result = api::list_course_module_competencies_in_course_module($cm->id);
2685         $this->assertEquals($result[0]->get_competencyid(), $c->get_id());
2686         $this->assertEquals($result[1]->get_competencyid(), $c2->get_id());
2687     }
2689     /**
2690      * Test update ruleoutcome for course_competency.
2691      */
2692     public function test_set_ruleoutcome_course_competency() {
2693         $this->resetAfterTest(true);
2694         $dg = $this->getDataGenerator();
2695         $lpg = $dg->get_plugin_generator('core_competency');
2696         $u1 = $dg->create_user();
2697         $u2 = $dg->create_user();
2698         $course = $dg->create_course();
2700         $this->setAdminUser();
2701         $f = $lpg->create_framework();
2702         $c = $lpg->create_competency(array('competencyframeworkid' => $f->get_id()));
2703         $cc = api::add_competency_to_course($course->id, $c->get_id());
2705         // Check record was created with default rule value Evidence.
2706         $this->assertEquals(1, \core_competency\course_competency::count_records());
2707         $recordscc = api::list_course_competencies($course->id);
2708         $this->assertEquals(\core_competency\course_competency::OUTCOME_EVIDENCE,
2709             $recordscc[0]['coursecompetency']->get_ruleoutcome());
2711         // Check ruleoutcome value is updated to None.
2712         $this->assertTrue(api::set_course_competency_ruleoutcome($recordscc[0]['coursecompetency']->get_id(),
2713             \core_competency\course_competency::OUTCOME_NONE));
2714         $recordscc = api::list_course_competencies($course->id);
2715         $this->assertEquals(\core_competency\course_competency::OUTCOME_NONE, $recordscc[0]['coursecompetency']->get_ruleoutcome());
2716     }
2718     /**
2719      * Test validation on grade on user_competency.
2720      */
2721     public function test_validate_grade_in_user_competency() {
2722         global $DB;
2724         $this->resetAfterTest(true);
2725         $this->setAdminUser();
2726         $dg = $this->getDataGenerator();
2727         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
2728         $user = $dg->create_user();
2730         $s1 = $dg->create_scale(array("scale" => "value1, value2"));
2731         $s2 = $dg->create_scale(array("scale" => "value3, value4, value5, value6"));
2733         $scaleconfiguration1 = '[{"scaleid":"'.$s1->id.'"},{"name":"value1","id":1,"scaledefault":1,"proficient":0},' .
2734                 '{"name":"value2","id":2,"scaledefault":0,"proficient":1}]';
2735         $scaleconfiguration2 = '[{"scaleid":"'.$s2->id.'"},{"name":"value3","id":1,"scaledefault":1,"proficient":0},'
2736                 . '{"name":"value4","id":2,"scaledefault":0,"proficient":1}]';
2738         // Create a framework with scale configuration1.
2739         $frm = array(
2740             'scaleid' => $s1->id,
2741             'scaleconfiguration' => $scaleconfiguration1
2742         );
2743         $framework = $lpg->create_framework($frm);
2744         $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
2746         // Create competency with its own scale configuration.
2747         $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id(),
2748                                             'scaleid' => $s2->id,
2749                                             'scaleconfiguration' => $scaleconfiguration2
2750                                         ));
2752         // Detecte invalid grade in competency using its framework competency scale.
2753         try {
2754             $usercompetency = new user_competency(0, (object) array('userid' => $user->id, 'competencyid' => $c1->get_id(),
2755                 'proficiency' => true, 'grade' => 3 ));
2756             $usercompetency->create();
2757             $this->fail('Invalid grade not detected in framework scale');
2758         } catch (\core_competency\invalid_persistent_exception $e) {
2759             $this->assertTrue(true);
2760         }
2762         // Detecte invalid grade in competency using its own scale.
2763         try {
2764             $usercompetency = new user_competency(0, (object) array('userid' => $user->id, 'competencyid' => $c2->get_id(),
2765                 'proficiency' => true, 'grade' => 5 ));
2766             $usercompetency->create();
2767             $this->fail('Invalid grade not detected in competency scale');
2768         } catch (\core_competency\invalid_persistent_exception $e) {
2769             $this->assertTrue(true);
2770         }
2772         // Accept valid grade in competency using its framework competency scale.
2773         try {
2774             $usercompetency = new user_competency(0, (object) array('userid' => $user->id, 'competencyid' => $c1->get_id(),
2775                 'proficiency' => true, 'grade' => 1 ));
2776             $usercompetency->create();
2777             $this->assertTrue(true);
2778         } catch (\core_competency\invalid_persistent_exception $e) {
2779             $this->fail('Valide grade rejected in framework scale');
2780         }
2782         // Accept valid grade in competency using its framework competency scale.
2783         try {
2784             $usercompetency = new user_competency(0, (object) array('userid' => $user->id, 'competencyid' => $c2->get_id(),
2785                 'proficiency' => true, 'grade' => 4 ));
2786             $usercompetency->create();
2787             $this->assertTrue(true);
2788         } catch (\core_competency\invalid_persistent_exception $e) {
2789             $this->fail('Valide grade rejected in competency scale');
2790         }
2791     }
2793     /**
2794      * Test when adding competency that belong to hidden framework to plan/template/course.
2795      */
2796     public function test_hidden_framework() {
2797         $this->resetAfterTest(true);
2798         $this->setAdminUser();
2799         $dg = $this->getDataGenerator();
2800         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
2801         $user = $dg->create_user();
2803         // Create a course.
2804         $cat1 = $dg->create_category();
2805         $course = $dg->create_course(array('category' => $cat1->id));
2806         // Create a template.
2807         $template = $lpg->create_template();
2808         // Create a plan.
2809         $plan = $lpg->create_plan(array('userid' => $user->id));
2811         // Create a hidden framework.
2812         $frm = array(
2813             'visible' => false
2814         );
2815         $framework = $lpg->create_framework($frm);
2816         $competency = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
2818         // Linking competency that belong to hidden framework to course.
2819         try {
2820             api::add_competency_to_course($course->id, $competency->get_id());
2821             $this->fail('A competency belonging to hidden framework can not be linked to course');
2822         } catch (coding_exception $e) {
2823             $this->assertTrue(true);
2824         }
2826         // Adding competency that belong to hidden framework to template.
2827         try {
2828             api::add_competency_to_template($template->get_id(), $competency->get_id());
2829             $this->fail('A competency belonging to hidden framework can not be added to template');
2830         } catch (coding_exception $e) {
2831             $this->assertTrue(true);
2832         }
2834         // Adding competency that belong to hidden framework to plan.
2835         try {
2836             api::add_competency_to_plan($plan->get_id(), $competency->get_id());
2837             $this->fail('A competency belonging to hidden framework can not be added to plan');
2838         } catch (coding_exception $e) {
2839             $this->assertTrue(true);
2840         }
2841     }
2843     /**
2844      * Test when using hidden template in plan/cohort.
2845      */
2846     public function test_hidden_template() {
2847         $this->resetAfterTest(true);
2848         $this->setAdminUser();
2849         $dg = $this->getDataGenerator();
2850         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
2851         $user = $dg->create_user();
2853         // Create a cohort.
2854         $cohort = $dg->create_cohort();
2855         // Create a hidden template.
2856         $template = $lpg->create_template(array('visible' => false));
2858         // Can not link hidden template to plan.
2859         try {
2860             api::create_plan_from_template($template->get_id(), $user->id);
2861             $this->fail('Can not link a hidden template to plan');
2862         } catch (coding_exception $e) {
2863             $this->assertTrue(true);
2864         }
2866         // Can associate hidden template to cohort.
2867         $templatecohort = api::create_template_cohort($template->get_id(), $cohort->id);
2868         $this->assertInstanceOf('\core_competency\template_cohort', $templatecohort);
2869     }
2871     /**
2872      * Test that completed plan created form a template does not change when template is modified.
2873      */
2874     public function test_completed_plan_doesnot_change() {
2875         global $DB;
2877         $this->resetAfterTest(true);
2878         $this->setAdminUser();
2879         $dg = $this->getDataGenerator();
2880         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
2881         $user = $dg->create_user();
2883         // Create a framework and assign competencies.
2884         $framework = $lpg->create_framework();
2885         $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
2886         $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
2887         $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
2888         $c4 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
2890         // Create template and assign competencies.
2891         $tp = $lpg->create_template();
2892         $tpc1 = $lpg->create_template_competency(array('templateid' => $tp->get_id(), 'competencyid' => $c1->get_id()));
2893         $tpc2 = $lpg->create_template_competency(array('templateid' => $tp->get_id(), 'competencyid' => $c2->get_id()));
2894         $tpc3 = $lpg->create_template_competency(array('templateid' => $tp->get_id(), 'competencyid' => $c3->get_id()));
2896         // Create a plan form template and change it status to complete.
2897         $plan = $lpg->create_plan(array('userid' => $user->id, 'templateid' => $tp->get_id()));
2898         api::complete_plan($plan);
2900         // Check user competency plan created correctly.
2901         $this->assertEquals(3, \core_competency\user_competency_plan::count_records());
2902         $ucp = \core_competency\user_competency_plan::get_records();
2903         $this->assertEquals($ucp[0]->get_competencyid(), $c1->get_id());
2904         $this->assertEquals($ucp[1]->get_competencyid(), $c2->get_id());
2905         $this->assertEquals($ucp[2]->get_competencyid(), $c3->get_id());
2907         // Add and remove a competency from the template.
2908         api::add_competency_to_template($tp->get_id(), $c4->get_id());
2909         api::remove_competency_from_template($tp->get_id(), $c1->get_id());
2911         // Check that user competency plan did not change.
2912         $competencies = $plan->get_competencies();
2913         $this->assertEquals(3, count($competencies));
2914         $ucp1 = array($c1->get_id(), $c2->get_id(), $c3->get_id());
2915         $ucp2 = array();
2916         foreach ($competencies as $id => $cmp) {
2917             $ucp2[] = $id;
2918         }
2919         $this->assertEquals(0, count(array_diff($ucp1, $ucp2)));
2920     }
2922     protected function setup_framework_for_reset_rules_tests() {
2923         $this->resetAfterTest(true);
2924         $dg = $this->getDataGenerator();
2925         $lpg = $dg->get_plugin_generator('core_competency');
2927         $this->setAdminUser();
2928         $f1 = $lpg->create_framework();
2929         $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
2930         $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c1->get_id()));
2931         $c1a1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c1a->get_id()));
2932         $c1a1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c1a1->get_id()));
2933         $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
2934         $c1b1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c1b->get_id()));
2935         $c1b1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c1b1->get_id()));
2936         $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
2937         $c2a = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
2939         $c1->set_ruleoutcome(competency::OUTCOME_EVIDENCE);
2940         $c1->set_ruletype('core_competency\\competency_rule_all');
2941         $c1->update();
2942         $c1a->set_ruleoutcome(competency::OUTCOME_EVIDENCE);
2943         $c1a->set_ruletype('core_competency\\competency_rule_all');
2944         $c1a->update();
2945         $c1a1->set_ruleoutcome(competency::OUTCOME_EVIDENCE);
2946         $c1a1->set_ruletype('core_competency\\competency_rule_all');
2947         $c1a1->update();
2948         $c1b->set_ruleoutcome(competency::OUTCOME_EVIDENCE);
2949         $c1b->set_ruletype('core_competency\\competency_rule_all');
2950         $c1b->update();
2951         $c2->set_ruleoutcome(competency::OUTCOME_EVIDENCE);
2952         $c2->set_ruletype('core_competency\\competency_rule_all');
2953         $c2->update();
2955         return array(
2956             'f1' => $f1,
2957             'c1' => $c1,
2958             'c1a' => $c1a,
2959             'c1a1' => $c1a1,
2960             'c1a1a' => $c1a1a,
2961             'c1b' => $c1b,
2962             'c1b1' => $c1b1,
2963             'c1b1a' => $c1b1a,
2964             'c2' => $c2,
2965             'c2a' => $c2a,
2966         );
2967     }
2969     public function test_moving_competency_reset_rules_updown() {
2970         $data = $this->setup_framework_for_reset_rules_tests();
2971         $f1 = $data['f1'];
2972         $c1 = $data['c1'];
2973         $c1a = $data['c1a'];
2974         $c1a1 = $data['c1a1'];
2975         $c1a1a = $data['c1a1a'];
2976         $c1b = $data['c1b'];
2977         $c1b1 = $data['c1b1'];
2978         $c1b1a = $data['c1b1a'];
2979         $c2 = $data['c2'];
2980         $c2a = $data['c2a'];
2982         // Moving up and down doesn't change anything.
2983         api::move_down_competency($c1a->get_id());
2984         $c1->read();
2985         $c1a->read();
2986         $c1a1->read();
2987         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1->get_ruleoutcome());
2988         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get_ruleoutcome());
2989         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get_ruleoutcome());
2990         api::move_up_competency($c1a->get_id());
2991         $c1->read();
2992         $c1a->read();
2993         $c1a1->read();
2994         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1->get_ruleoutcome());
2995         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get_ruleoutcome());
2996         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get_ruleoutcome());
2997     }
2999     public function test_moving_competency_reset_rules_parent() {
3000         $data = $this->setup_framework_for_reset_rules_tests();
3001         $f1 = $data['f1'];
3002         $c1 = $data['c1'];
3003         $c1a = $data['c1a'];
3004         $c1a1 = $data['c1a1'];
3005         $c1a1a = $data['c1a1a'];
3006         $c1b = $data['c1b'];
3007         $c1b1 = $data['c1b1'];
3008         $c1b1a = $data['c1b1a'];
3009         $c2 = $data['c2'];
3010         $c2a = $data['c2a'];
3012         // Moving out of parent will reset the parent, and the destination.
3013         api::set_parent_competency($c1a->get_id(), $c1b->get_id());
3014         $c1->read();
3015         $c1a->read();
3016         $c1a1->read();
3017         $c1b->read();
3018         $c2->read();
3019         $this->assertEquals(competency::OUTCOME_NONE, $c1->get_ruleoutcome());
3020         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get_ruleoutcome());
3021         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get_ruleoutcome());
3022         $this->assertEquals(competency::OUTCOME_NONE, $c1b->get_ruleoutcome());
3023         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get_ruleoutcome());
3024     }
3026     public function test_moving_competency_reset_rules_totoplevel() {
3027         $data = $this->setup_framework_for_reset_rules_tests();
3028         $f1 = $data['f1'];
3029         $c1 = $data['c1'];
3030         $c1a = $data['c1a'];
3031         $c1a1 = $data['c1a1'];
3032         $c1a1a = $data['c1a1a'];
3033         $c1b = $data['c1b'];
3034         $c1b1 = $data['c1b1'];
3035         $c1b1a = $data['c1b1a'];
3036         $c2 = $data['c2'];
3037         $c2a = $data['c2a'];
3039         // Moving to top level only affects the initial parent.
3040         api::set_parent_competency($c1a1->get_id(), 0);
3041         $c1->read();
3042         $c1a->read();
3043         $c1a1->read();
3044         $c1b->read();
3045         $c2->read();
3046         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1->get_ruleoutcome());
3047         $this->assertEquals(competency::OUTCOME_NONE, $c1a->get_ruleoutcome());
3048         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get_ruleoutcome());
3049         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get_ruleoutcome());
3050         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get_ruleoutcome());
3051     }
3053     public function test_moving_competency_reset_rules_fromtoplevel() {
3054         $data = $this->setup_framework_for_reset_rules_tests();
3055         $f1 = $data['f1'];
3056         $c1 = $data['c1'];
3057         $c1a = $data['c1a'];
3058         $c1a1 = $data['c1a1'];
3059         $c1a1a = $data['c1a1a'];
3060         $c1b = $data['c1b'];
3061         $c1b1 = $data['c1b1'];
3062         $c1b1a = $data['c1b1a'];
3063         $c2 = $data['c2'];
3064         $c2a = $data['c2a'];
3066         // Moving from top level only affects the destination parent.
3067         api::set_parent_competency($c2->get_id(), $c1a1->get_id());
3068         $c1->read();
3069         $c1a->read();
3070         $c1a1->read();
3071         $c1b->read();
3072         $c2->read();
3073         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1->get_ruleoutcome());
3074         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get_ruleoutcome());
3075         $this->assertEquals(competency::OUTCOME_NONE, $c1a1->get_ruleoutcome());
3076         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get_ruleoutcome());
3077         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get_ruleoutcome());
3078     }
3080     public function test_moving_competency_reset_rules_child() {
3081         $data = $this->setup_framework_for_reset_rules_tests();
3082         $f1 = $data['f1'];
3083         $c1 = $data['c1'];
3084         $c1a = $data['c1a'];
3085         $c1a1 = $data['c1a1'];
3086         $c1a1a = $data['c1a1a'];
3087         $c1b = $data['c1b'];
3088         $c1b1 = $data['c1b1'];
3089         $c1b1a = $data['c1b1a'];
3090         $c2 = $data['c2'];
3091         $c2a = $data['c2a'];
3093         // Moving to a child of self resets self, parent and destination.
3094         api::set_parent_competency($c1a->get_id(), $c1a1->get_id());
3095         $c1->read();
3096         $c1a->read();
3097         $c1a1->read();
3098         $c1b->read();
3099         $c2->read();
3100         $this->assertEquals(competency::OUTCOME_NONE, $c1->get_ruleoutcome());
3101         $this->assertEquals(competency::OUTCOME_NONE, $c1a->get_ruleoutcome());
3102         $this->assertEquals(competency::OUTCOME_NONE, $c1a1->get_ruleoutcome());
3103         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get_ruleoutcome());
3104         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get_ruleoutcome());
3105     }
3107     public function test_create_competency_reset_rules() {
3108         $data = $this->setup_framework_for_reset_rules_tests();
3109         $f1 = $data['f1'];
3110         $c1 = $data['c1'];
3111         $c1a = $data['c1a'];
3112         $c1a1 = $data['c1a1'];
3113         $c1a1a = $data['c1a1a'];
3114         $c1b = $data['c1b'];
3115         $c1b1 = $data['c1b1'];
3116         $c1b1a = $data['c1b1a'];
3117         $c2 = $data['c2'];
3118         $c2a = $data['c2a'];
3120         // Adding a new competency resets the rule of its parent.
3121         api::create_competency((object) array('shortname' => 'A', 'parentid' => $c1->get_id(), 'idnumber' => 'A',
3122             'competencyframeworkid' => $f1->get_id()));
3123         $c1->read();
3124         $c1a->read();
3125         $c1a1->read();
3126         $c1b->read();
3127         $c2->read();
3128         $this->assertEquals(competency::OUTCOME_NONE, $c1->get_ruleoutcome());
3129         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get_ruleoutcome());
3130         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get_ruleoutcome());
3131         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get_ruleoutcome());
3132         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get_ruleoutcome());
3133     }
3135     public function test_delete_competency_reset_rules() {
3136         $data = $this->setup_framework_for_reset_rules_tests();
3137         $f1 = $data['f1'];
3138         $c1 = $data['c1'];
3139         $c1a = $data['c1a'];
3140         $c1a1 = $data['c1a1'];
3141         $c1a1a = $data['c1a1a'];
3142         $c1b = $data['c1b'];
3143         $c1b1 = $data['c1b1'];
3144         $c1b1a = $data['c1b1a'];
3145         $c2 = $data['c2'];
3146         $c2a = $data['c2a'];
3148         // Deleting a competency resets the rule of its parent.
3149         api::delete_competency($c1a->get_id());
3150         $c1->read();
3151         $c1b->read();
3152         $c2->read();
3153         $this->assertEquals(competency::OUTCOME_NONE, $c1->get_ruleoutcome());
3154         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get_ruleoutcome());
3155         $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get_ruleoutcome());
3156     }
3158     public function test_template_has_related_data() {
3159         $this->resetAfterTest(true);
3160         $this->setAdminUser();
3162         $dg = $this->getDataGenerator();
3163         $user = $dg->create_user();
3164         $lpg = $dg->get_plugin_generator('core_competency');
3165         $tpl1 = $lpg->create_template();
3166         $tpl2 = $lpg->create_template();
3168         // Create plans for first template.
3169         $time = time();
3170         $plan1 = $lpg->create_plan(array('templateid' => $tpl1->get_id(), 'userid' => $user->id,
3171             'name' => 'Not good name', 'duedate' => $time + 3600, 'description' => 'Ahah', 'descriptionformat' => FORMAT_PLAIN));
3173         $this->assertTrue(api::template_has_related_data($tpl1->get_id()));
3174         $this->assertFalse(api::template_has_related_data($tpl2->get_id()));
3176     }
3178     public function test_delete_template_delete_plans() {
3179         $this->resetAfterTest(true);
3180         $this->setAdminUser();
3182         $dg = $this->getDataGenerator();
3183         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
3185         $u1 = $dg->create_user();
3186         $f = $lpg->create_framework();
3187         $c1 = $lpg->create_competency(array('competencyframeworkid' => $f->get_id()));
3188         $c2 = $lpg->create_competency(array('competencyframeworkid' => $f->get_id()));
3190         $tpl = $lpg->create_template();
3192         $tplc1 = $lpg->create_template_competency(array('templateid' => $tpl->get_id(), 'competencyid' => $c1->get_id(),
3193             'sortorder' => 1));
3194         $tplc2 = $lpg->create_template_competency(array('templateid' => $tpl->get_id(), 'competencyid' => $c2->get_id(),
3195             'sortorder' => 2));
3197         $p1 = $lpg->create_plan(array('templateid' => $tpl->get_id(), 'userid' => $u1->id));
3199         // Check pre-test.
3200         $this->assertTrue(\core_competency\template::record_exists($tpl->get_id()));
3201         $this->assertEquals(2, \core_competency\template_competency::count_competencies($tpl->get_id()));
3202         $this->assertEquals(1, count(\core_competency\plan::get_records(array('templateid' => $tpl->get_id()))));
3204         $result = api::delete_template($tpl->get_id(), true);
3205         $this->assertTrue($result);
3207         // Check that the template does not exist anymore.
3208         $this->assertFalse(\core_competency\template::record_exists($tpl->get_id()));
3210         // Check that associated competencies are also deleted.
3211         $this->assertEquals(0, \core_competency\template_competency::count_competencies($tpl->get_id()));
3213         // Check that associated plan are also deleted.
3214         $this->assertEquals(0, count(\core_competency\plan::get_records(array('templateid' => $tpl->get_id()))));
3215     }
3217     public function test_delete_template_unlink_plans() {
3218         $this->resetAfterTest(true);
3219         $this->setAdminUser();
3221         $dg = $this->getDataGenerator();
3222         $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
3224         $u1 = $dg->create_user();
3225         $f = $lpg->create_framework();
3226         $c1 = $lpg->create_competency(array('competencyframeworkid' => $f->get_id()));
3227         $c2 = $lpg->create_competency(array('competencyframeworkid' => $f->get_id()));
3229         $tpl = $lpg->create_template();
3231         $tplc1 = $lpg->create_template_competency(array('templateid' => $tpl->get_id(), 'competencyid' => $c1->get_id(),
3232             'sortorder' => 1));
3233         $tplc2 = $lpg->create_template_competency(array('templateid' => $tpl->get_id(), 'competencyid' => $c2->get_id(),
3234             'sortorder' => 2));
3236         $p1 = $lpg->create_plan(array('templateid' => $tpl->get_id(), 'userid' => $u1->id));
3238         // Check pre-test.
3239         $this->assertTrue(\core_competency\template::record_exists($tpl->get_id()));
3240         $this->assertEquals(2, \core_competency\template_competency::count_competencies($tpl->get_id()));
3241         $this->assertEquals(1, count(\core_competency\plan::get_records(array('templateid' => $tpl->get_id()))));
3243         $result = api::delete_template($tpl->get_id(), false);
3244         $this->assertTrue($result);
3246         // Check that the template does not exist anymore.
3247         $this->assertFalse(\core_competency\template::record_exists($tpl->get_id()));
3249         // Check that associated competencies are also deleted.
3250         $this->assertEquals(0, \core_competency\template_competency::count_competencies($tpl->get_id()));
3252         // Check that associated plan still exist but unlink from template.
3253         $plans = \core_competency\plan::get_records(array('id' => $p1->get_id()));
3254         $this->assertEquals(1, count($plans));
3255         $this->assertEquals($plans[0]->get_origtemplateid(), $tpl->get_id());
3256         $this->assertNull($plans[0]->get_templateid());
3257     }
3259     public function test_delete_competency() {
3260         $this->resetAfterTest(true);
3261         $dg = $this->getDataGenerator();
3262         $lpg = $dg->get_plugin_generator('core_competency');
3263         $this->setAdminUser();
3265         $u1 = $dg->create_user();
3267         $f1 = $lpg->create_framework();
3268         $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
3269         $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
3270         $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c1->get_id()));
3271         $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c1a->get_id()));
3272         $c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c1b->get_id()));
3273         $c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id(), 'parentid' => $c1b->get_id()));