Skip to content

Commit

Permalink
MDL-51647 tool_lp: New task to close plans which are due
Browse files Browse the repository at this point in the history
  • Loading branch information
Frederic Massart committed Apr 18, 2016
1 parent 5f9fa9f commit 5bfab68
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 15 deletions.
56 changes: 50 additions & 6 deletions admin/tool/lp/classes/api.php
Expand Up @@ -1279,15 +1279,14 @@ public static function update_plan(stdClass $record) {
throw new required_capability_exception($context, 'tool/lp:planmanage', 'nopermissions', '');
}

// Are we trying to set the plan as complete?
if ($plan->get_status() == plan::STATUS_COMPLETE && $beforestatus != plan::STATUS_COMPLETE) {
throw new coding_exception('To set a plan as complete api::complete_plan() must be used.');
}

// Wrap the updates in a DB transaction.
$transaction = $DB->start_delegated_transaction();

// Archive user competencies if the status of the plan is changed to complete.
$mustarchivecompetencies = ($plan->get_status() == plan::STATUS_COMPLETE && $beforestatus != plan::STATUS_COMPLETE);
if ($mustarchivecompetencies) {
self::archive_user_competencies_in_plan($plan);
}

// Delete archived user competencies if the status of the plan is changed from complete to another status.
$mustremovearchivedcompetencies = ($beforestatus == plan::STATUS_COMPLETE && $plan->get_status() != plan::STATUS_COMPLETE);
if ($mustremovearchivedcompetencies) {
Expand Down Expand Up @@ -1349,6 +1348,51 @@ public static function delete_plan($id) {
return $success;
}

/**
* Complete a plan.
*
* @param int|plan $planorid The plan, or its ID.
* @return bool
*/
public static function complete_plan($planorid) {
global $DB;

$plan = $planorid;
if (!is_object($planorid)) {
$plan = new plan($planorid);
}

// Validate that the plan can be managed.
if (!$plan->can_manage()) {
throw new required_capability_exception($plan->get_context(), 'tool/lp:planmanage', 'nopermissions', '');
}

// Check if the plan was already completed.
if ($plan->get_status() == plan::STATUS_COMPLETE) {
throw new coding_exception('The plan is already complete.');
}

$plan->set_status(plan::STATUS_COMPLETE);

// The user should also be able to manage the plan when it's completed.
if (!$plan->can_manage()) {
throw new required_capability_exception($plan->get_context(), 'tool/lp:planmanage', 'nopermissions', '');
}

// Do the things.
$transaction = $DB->start_delegated_transaction();
self::archive_user_competencies_in_plan($plan);
$success = $plan->update();

if (!$success) {
$transaction->rollback(new moodle_exception('The plan could not be updated.'));
return $success;
}

$transaction->allow_commit();
return $success;
}

/**
* List the competencies in a user plan.
*
Expand Down
12 changes: 12 additions & 0 deletions admin/tool/lp/classes/plan.php
Expand Up @@ -252,6 +252,18 @@ public static function can_read_user_draft($planuserid) {
|| self::can_manage_user_draft($planuserid);
}

/**
* Get the recordset of the plans that are due and incomplete.
*
* @return \moodle_recordset
*/
public static function get_recordset_for_due_and_incomplete() {
global $DB;
$sql = "duedate > 0 AND duedate < :now AND status != :status";
$params = array('now' => time(), 'status' => self::STATUS_COMPLETE);
return $DB->get_recordset_select(self::TABLE, $sql, $params);
}

/**
* Return a list of status depending on capabilities.
*
Expand Down
64 changes: 64 additions & 0 deletions admin/tool/lp/classes/task/complete_plans_task.php
@@ -0,0 +1,64 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* Complete plans task.
*
* @package tool_lp
* @copyright 2015 Frédéric Massart - FMCorz.net
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

namespace tool_lp\task;
defined('MOODLE_INTERNAL') || die();

use tool_lp\api;
use tool_lp\plan;

/**
* Complete plans task class.
*
* This task should run relatively often because the plans due dates can be set at
* any time of the day in any timezone.
*
* @package tool_lp
* @copyright 2015 Frédéric Massart - FMCorz.net
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class complete_plans_task extends \core\task\scheduled_task {

/**
* Get a descriptive name for this task.
*
* @return string
*/
public function get_name() {
return get_string('completeplanstask', 'tool_lp');
}

/**
* Do the job.
*/
public function execute() {
$records = plan::get_recordset_for_due_and_incomplete();
foreach ($records as $record) {
$plan = new plan(0, $record);
api::complete_plan($plan);
}
$records->close();
}

}
37 changes: 37 additions & 0 deletions admin/tool/lp/db/tasks.php
@@ -0,0 +1,37 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* Tasks definitions.
*
* @package tool_lp
* @copyright 2015 Frédéric Massart - FMCorz.net
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

defined('MOODLE_INTERNAL') || die();

$tasks = array(
array(
'classname' => 'tool_lp\task\complete_plans_task',
'blocking' => 0,
'minute' => 'R',
'hour' => '*',
'day' => '*',
'dayofweek' => '*',
'month' => '*'
),
);
1 change: 1 addition & 0 deletions admin/tool/lp/lang/en/tool_lp.php
Expand Up @@ -47,6 +47,7 @@
$string['competencyrelatedcompetencies'] = '{$a} related competencies';
$string['competencyrule'] = 'Competency rule';
$string['competencyupdated'] = 'Competency updated';
$string['completeplanstask'] = 'Complete plans which are due';
$string['configurescale'] = 'Configure scales';
$string['coursecompetencies'] = 'Course competencies';
$string['coursesusingthiscompetency'] = 'Courses using this competency';
Expand Down
88 changes: 80 additions & 8 deletions admin/tool/lp/tests/api_test.php
Expand Up @@ -411,14 +411,87 @@ public function test_update_plan() {
'status' => \tool_lp\plan::STATUS_ACTIVE
);
$plan = api::create_plan((object)$plan);

// Silently transition to complete status to avoid errors about transitioning to complete.
$plan->set_status(\tool_lp\plan::STATUS_COMPLETE);
$plan->update();

$record = $plan->to_record();
$record->name = 'plan create own modified';
$record->status = \tool_lp\plan::STATUS_COMPLETE;
$plan = api::update_plan($record);
$this->assertInstanceOf('\tool_lp\plan', $plan);

}

/**
* Test that the method to complete a plan.
*/
public function test_complete_plan() {
global $DB;

$this->resetAfterTest(true);
$this->setAdminUser();
$dg = $this->getDataGenerator();
$lpg = $this->getDataGenerator()->get_plugin_generator('tool_lp');
$user = $dg->create_user();

// Create a framework and assign competencies.
$framework = $lpg->create_framework();
$c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
$c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
$c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));

// Create two plans and assign competencies.
$plan = $lpg->create_plan(array('userid' => $user->id));
$otherplan = $lpg->create_plan(array('userid' => $user->id));

$lpg->create_plan_competency(array('planid' => $plan->get_id(), 'competencyid' => $c1->get_id()));
$lpg->create_plan_competency(array('planid' => $plan->get_id(), 'competencyid' => $c2->get_id()));
$lpg->create_plan_competency(array('planid' => $plan->get_id(), 'competencyid' => $c3->get_id()));
$lpg->create_plan_competency(array('planid' => $otherplan->get_id(), 'competencyid' => $c1->get_id()));

$uclist = array(
$lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c1->get_id(),
'proficiency' => true, 'grade' => 1 )),
$lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c2->get_id(),
'proficiency' => false, 'grade' => 2 ))
);

$this->assertEquals(2, \tool_lp\user_competency::count_records());
$this->assertEquals(0, \tool_lp\user_competency_plan::count_records());

// Change status of the plan to complete.
api::complete_plan($plan);

// Check that user competencies are now in user_competency_plan objects and still in user_competency.
$this->assertEquals(2, \tool_lp\user_competency::count_records());
$this->assertEquals(3, \tool_lp\user_competency_plan::count_records());

$usercompetenciesplan = \tool_lp\user_competency_plan::get_records();

$this->assertEquals($uclist[0]->get_userid(), $usercompetenciesplan[0]->get_userid());
$this->assertEquals($uclist[0]->get_competencyid(), $usercompetenciesplan[0]->get_competencyid());
$this->assertEquals($uclist[0]->get_proficiency(), (bool) $usercompetenciesplan[0]->get_proficiency());
$this->assertEquals($uclist[0]->get_grade(), $usercompetenciesplan[0]->get_grade());
$this->assertEquals($plan->get_id(), $usercompetenciesplan[0]->get_planid());

$this->assertEquals($uclist[1]->get_userid(), $usercompetenciesplan[1]->get_userid());
$this->assertEquals($uclist[1]->get_competencyid(), $usercompetenciesplan[1]->get_competencyid());
$this->assertEquals($uclist[1]->get_proficiency(), (bool) $usercompetenciesplan[1]->get_proficiency());
$this->assertEquals($uclist[1]->get_grade(), $usercompetenciesplan[1]->get_grade());
$this->assertEquals($plan->get_id(), $usercompetenciesplan[1]->get_planid());

$this->assertEquals($user->id, $usercompetenciesplan[2]->get_userid());
$this->assertEquals($c3->get_id(), $usercompetenciesplan[2]->get_competencyid());
$this->assertNull($usercompetenciesplan[2]->get_proficiency());
$this->assertNull($usercompetenciesplan[2]->get_grade());
$this->assertEquals($plan->get_id(), $usercompetenciesplan[2]->get_planid());

// Completing a plan that is completed throws an exception.
$this->setExpectedException('coding_exception');
api::complete_plan($plan);
}

/**
* Test update plan and the managing of archived user competencies.
*/
Expand Down Expand Up @@ -478,7 +551,12 @@ public function test_update_plan_manage_archived_competencies() {
$record = $plan->to_record();
$record->status = \tool_lp\plan::STATUS_COMPLETE;

$plan = api::update_plan($record);
try {
$plan = api::update_plan($record);
$this->fail('We cannot complete a plan using api::update_plan().');
} catch (coding_exception $e) {
}
api::complete_plan($plan);

// Check that user compretencies are now in user_competency_plan objects and still in user_competency.
$this->assertEquals(2, \tool_lp\user_competency::count_records());
Expand All @@ -504,12 +582,6 @@ public function test_update_plan_manage_archived_competencies() {
$this->assertNull($usercompetenciesplan[2]->get_grade());
$this->assertEquals($plan->get_id(), $usercompetenciesplan[2]->get_planid());

$plan = api::update_plan($record);

// Check that nothing is done if re-updating plan with same status.
$this->assertEquals(2, \tool_lp\user_competency::count_records());
$this->assertEquals(3, \tool_lp\user_competency_plan::count_records());

// Change status of the plan to active.
$record = $plan->to_record();
$record->status = \tool_lp\plan::STATUS_ACTIVE;
Expand Down
2 changes: 1 addition & 1 deletion admin/tool/lp/version.php
Expand Up @@ -25,7 +25,7 @@
defined('MOODLE_INTERNAL') || die();


$plugin->version = 2015111005; // The current plugin version (Date: YYYYMMDDXX).
$plugin->version = 2015111010; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2014110400; // Requires this Moodle version.
$plugin->component = 'tool_lp'; // Full name of the plugin (used for diagnostics).

0 comments on commit 5bfab68

Please sign in to comment.