diff --git a/docs/StudentHealthTracking.md b/docs/StudentHealthTracking.md index 20b2fa9b..081791b9 100644 --- a/docs/StudentHealthTracking.md +++ b/docs/StudentHealthTracking.md @@ -61,4 +61,14 @@ the Death Information panel will appear so you can also input the Cause of Death sent. View the **Cause of Death Report** and the **Student Health Report** by navigating to the Reports module and clicking -on the appropriate report title. \ No newline at end of file +on the appropriate report title. + +## Common Student Injuries dashlet +A new dashlet is available to track the number of times Students are injured over time. This dashlet leverages +the Contacts Audit table to populate a pie chart summarizing the number of times Students for in a given Super Group (or all Super Groups) enter a non-active Vital Status. + +This dashlet displays use of the Sucrose charts in a custom dashlet and is available in Home, List Views, and Record Views. + +There is also an accompanying API endpoint for retrieve the data from the Student records and shows use of Doctrine QueryBuilder in a complex parameterized query that can't be created using SugarQuery APIs. For more information on the endpoint see /rest/v11/help. + +The pull request for the Student vitals dashlet can be viewed in [#27](https://github.com/sugarcrm/school/pull/27). diff --git a/package/pack.php b/package/pack.php index f4ff487d..b8a3fbf4 100755 --- a/package/pack.php +++ b/package/pack.php @@ -199,7 +199,7 @@ 'default_value' => 'active', 'date_modified' => '2018-02-01 21:32:16', 'deleted' => '0', - 'audited' => '0', + 'audited' => '1', 'mass_update' => '1', 'duplicate_merge' => '1', 'reportable' => '1', diff --git a/package/src/custom/Extension/application/Ext/Language/en_us.student_vitals_dashboard.php b/package/src/custom/Extension/application/Ext/Language/en_us.student_vitals_dashboard.php new file mode 100644 index 00000000..f448af1e --- /dev/null +++ b/package/src/custom/Extension/application/Ext/Language/en_us.student_vitals_dashboard.php @@ -0,0 +1,5 @@ + 'Injuries', + 'comatose' => 'Comas', + 'deceased' => 'Deaths', +); diff --git a/package/src/custom/clients/base/api/StudentVitalsApi.php b/package/src/custom/clients/base/api/StudentVitalsApi.php new file mode 100644 index 00000000..37711054 --- /dev/null +++ b/package/src/custom/clients/base/api/StudentVitalsApi.php @@ -0,0 +1,83 @@ + array( + 'reqType' => 'GET', + 'noLoginRequired' => false, + 'path' => array('professorM', 'getStudentVitalData', '?'), + 'pathVars' => array('', '', 'supergroup'), + 'method' => 'getStudentVitalData', + 'shortHelp' => 'API End point to retrieve data for vitals dashlet', + 'longHelp' => 'custom/include/api/help/student_vitals_api_help.html', + ), + ); + } + + /** + * API Endpoint for student vitals chart + * @param $api + * @param $args + * + * @return false|string + * @throws SugarQueryException + */ + public function getStudentVitalData($api, $args) + { + + global $app_list_strings; + $supergroup = $args['supergroup']; + $helper = new \Sugarcrm\Sugarcrm\custom\inc\ProfessorM\StudentVitalHelper(); + $status_data = $helper->countStudentIncidents($supergroup); + + + // Sort if we have an array + if (is_array($status_data)) { + arsort($status_data); + } + $chart_data = array(); + + $seriesIdx = 1; + foreach ($status_data as $key => $value) { + if (!empty($key)) { + + $app_list_strings['problems_list'][$key]; + + $chart_data[] = array( + "key" => $app_list_strings['problems_list'][$key], + "value" => $value, + "total" => $value, + "seriesIndex" => $seriesIdx++ + ); + } + + } + + $title = ''; + if($supergroup != 'all') { + $sg = BeanFactory::retrieveBean("Accounts", $supergroup); + $title = "$sg->name Student Problems"; + } else { + $title = "All Student Problems"; + } + + $data = array( + "properties" => array( + "title" => $title, + "seriesName" => "Problems" + ), + "data"=> $chart_data + + + ); + + + return $data; + + } + +} diff --git a/package/src/custom/clients/base/views/student-vital-chart/student-vital-chart.hbs b/package/src/custom/clients/base/views/student-vital-chart/student-vital-chart.hbs new file mode 100644 index 00000000..ab0eecec --- /dev/null +++ b/package/src/custom/clients/base/views/student-vital-chart/student-vital-chart.hbs @@ -0,0 +1,6 @@ +
+
+ +
+ +
diff --git a/package/src/custom/clients/base/views/student-vital-chart/student-vital-chart.js b/package/src/custom/clients/base/views/student-vital-chart/student-vital-chart.js new file mode 100644 index 00000000..3df98153 --- /dev/null +++ b/package/src/custom/clients/base/views/student-vital-chart/student-vital-chart.js @@ -0,0 +1,130 @@ +/* + * Your installation or use of this SugarCRM file is subject to the applicable + * terms available at + * http://support.sugarcrm.com/Resources/Master_Subscription_Agreements/. + * If you do not agree to all of the applicable terms or do not have the + * authority to bind the entity as an authorized representative, then do not + * install or use this SugarCRM file. + * + * Copyright (C) SugarCRM Inc. All rights reserved. + */ +({ + plugins: ['Dashlet', 'Chart'], + className: 'student-vital-chart', + chartCollection: null, + hasData: false, + total: 0, + + /** + * @inheritdoc + */ + initialize: function(options) { + this._super('initialize', [options]); + + this.chart = sucrose.charts.pieChart() + .donut(true) + .donutLabelsOutside(true) + .donutRatio(0.25) + .hole(false) + .showTitle(true) + .tooltips(true) + .showLegend(true) + .colorData('class') + .tooltipContent(_.bind(function(eo, properties) { + + var value = parseInt(this.chart.getValue()(eo), 10); + var total = parseInt(properties.total, 10); + (total == 0) ? total = 1 : ''; + var percentage = value/total * 100; + return '

' + this.chart.fmtKey()(eo) + '

' + + '

' + value + '

' + + '

' + percentage.toFixed(2) + '%

'; + }, this)) + .strings({ + noData: app.lang.get('No Problems') + }); + }, + + /** + * Override to set options for supergroup selector in config dynamically + */ + initDashlet: function() { + if (this.meta.config) { + + var supergroup_value = this.meta.vitals_dashlet_supergroup ? this.meta.vitals_dashlet_supergroup : 'all'; + var accounts = app.data.createBeanCollection('Accounts'); + var supergroups = []; + supergroups.push({id: 'all', text:'All'}) + accounts.fetch({ + success: function() { + accounts.comparator = 'name'; + accounts.sort({silent: true}); + _.each(accounts.models, function(account){ + supergroups.push({id: account.id, text: account.attributes.name}); + }); + + $('[name="vitals_dashlet_supergroup"]').html('').select2({data: supergroups, width: '100%'}); + $('[name="vitals_dashlet_supergroup"]').val(supergroup_value).trigger('change'); + } + }) + } + + this._super('initDashlet'); + }, + + + /** + * Generic method to render chart with check for visibility and data. + * Called by _renderHtml and loadData. + */ + renderChart: function() { + var self = this; + if (!self.isChartReady()) { + return; + } + + d3sugar.select(this.el).select('svg#' + this.cid) + .datum(self.chartCollection) + .transition().duration(500) + .call(self.chart); + + this.chart_loaded = _.isFunction(this.chart.update); + this.displayNoData(!this.chart_loaded); + + }, + + /** + * @inheritdoc + */ + loadData: function(options) { + + if(this.meta.config) { + + return; + } + var self = this; + var supergroup_value = this.meta.vitals_dashlet_supergroup ? this.meta.vitals_dashlet_supergroup : 'all'; + url = app.api.buildURL('professorM/getStudentVitalData/' + supergroup_value); + this.hasData = false; + app.api.call('GET', url, null, { + success: function(data) { + self.hasData = true; + self.evaluateResponse(data); + self.render(); + }, + complete: options ? options.complete : null + }); + + }, + + + evaluateResponse: function(data) { + + this.total = 1; + this.hasData = true; + this.chartCollection = data; + + }, + + +})   diff --git a/package/src/custom/clients/base/views/student-vital-chart/student-vital-chart.php b/package/src/custom/clients/base/views/student-vital-chart/student-vital-chart.php new file mode 100644 index 00000000..389838d6 --- /dev/null +++ b/package/src/custom/clients/base/views/student-vital-chart/student-vital-chart.php @@ -0,0 +1,41 @@ + array( + array( + 'label' => 'LBL_STUDENT_VITAL_CHART', + 'description' => 'LBL_STUDENT_VITAL_CHART_DESC', + 'config' => array( + 'supergroup' => 'all', + ), + 'preview' => array( + ), + 'filter' => array( + 'view' => array( + 'records', + 'record' + ) + ), + + ), + + ), + 'panels' => array( + array( + 'name' => 'panel_body', + 'columns' => 2, + 'labelsOnTop' => true, + 'placeholders' => true, + 'fields' => array( + + array( + 'name' => 'vitals_dashlet_supergroup', + 'label' => 'LBL_VITALS_DASHLET_SELECT_TEAM', + 'type' => 'enum', + 'span' => 6, + 'options' => array('all' => 'All'), + ), + ), + ), + ), +); diff --git a/package/src/custom/include/ProfessorM/StudentVitalHelper.php b/package/src/custom/include/ProfessorM/StudentVitalHelper.php new file mode 100644 index 00000000..6fd64c8b --- /dev/null +++ b/package/src/custom/include/ProfessorM/StudentVitalHelper.php @@ -0,0 +1,72 @@ +getVitalChangeData($supergroup); + + foreach ($queryResults as $row) { + $pie[$row['problem']] = $row['count']; + } + + return $pie; + } + + + /** + * Query to retrieve student vitals transactions for given supergroup + * @param $supergroup + * + * @return array + * @throws \SugarQueryException + */ + public function getVitalChangeData($supergroup = 'all') + { + global $app_list_strings; + $results = array(); + $trackedStatuses = array_keys($app_list_strings['problems_list']); + + foreach($trackedStatuses as $status){ + $qb = $conn = $GLOBALS['db']->getConnection()->createQueryBuilder(); + $qb->from("contacts"); + $qb->innerJoin('contacts', 'contacts_audit', 'ca', "contacts.id=ca.parent_id"); + if ($supergroup != 'all') { + $qb ->join('contacts', 'accounts_contacts', 'ac', "contacts.id = ac.contact_id AND ac.account_id = :sg"); + $qb->setParameter('sg', $supergroup); + } + $qb->select("COUNT(*) AS count, ca.after_value_string AS problem"); + $qb->andWhere("contacts.deleted = 0"); + $qb->andWhere("ca.field_name = 'vitals_c'"); + $qb->andWhere("ca.after_value_string = :status"); + $qb->setParameter('status', $status); + $results = array_merge($results, $qb->execute()->fetchAll()); + } + return $results; + } + + +} diff --git a/package/src/custom/include/api/help/student_vitals_api_help.html b/package/src/custom/include/api/help/student_vitals_api_help.html new file mode 100644 index 00000000..02cad752 --- /dev/null +++ b/package/src/custom/include/api/help/student_vitals_api_help.html @@ -0,0 +1,123 @@ + +

Overview

+ + Get student vitals data for Student Vitals Dashlet + + +

+ + This endpoint is used for by the Student Vitals dashlet to poll the audit table on the Contacts table + for changes in the vitals_c field. The output is a summary of the number of problems encountered by Students + in a given Super Group over time. The results are formatted to the expected input for the Sucrose pie chart dashlet. + +

+ +

Request Arguments

+ + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
+ supergroup + + String + + Super Group to collect data from. Options are pulled in dynamically in Dashlet Config and the ID is passed. + Also can pass 'all' to get all Super Groups + + true +
+ +

Sample Request

+
+    rest/v11_4/professorM/getStudentVitalData/all
+
+ +

Response Arguments

+ + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
+ properties.title + + String + + Display name of the chart +
+ data + + Array + + An array of results grouped by vitals_c value and days in each status +
+ + + +

Response

+
+{
+	"properties": {
+		"title": "All Student Problems",
+		"seriesName": "Problems"
+	},
+	"data": [{
+		"key": "Injuries",
+		"value": 5,
+		"total": 5,
+		"seriesIndex": 1
+	}, {
+		"key": "Comas",
+		"value": 3,
+		"total": 3,
+		"seriesIndex": 2
+	}, {
+		"key": "Deaths",
+		"value": 3,
+		"total": 3,
+		"seriesIndex": 3
+	}]
+}
+
+ diff --git a/scripts/workspace/sugardocker b/scripts/workspace/sugardocker new file mode 160000 index 00000000..05e15c25 --- /dev/null +++ b/scripts/workspace/sugardocker @@ -0,0 +1 @@ +Subproject commit 05e15c25777276455b301b1d1369afcb39d9fb0f