mirror of
https://github.com/farmOS/farmOS.git
synced 2024-02-23 11:37:38 +01:00
Add farm_report module, simple CSV export of animal weights, simple graph of animal weights. #189
This commit is contained in:
commit
f13327f584
|
@ -0,0 +1,7 @@
|
|||
@media (min-width: 992px) {
|
||||
.farm-report-graph {
|
||||
float: right;
|
||||
margin-left: 1em;
|
||||
width: 50%;
|
||||
}
|
||||
}
|
|
@ -6,3 +6,4 @@ dependencies[] = farm_livestock
|
|||
dependencies[] = farm_inventory
|
||||
dependencies[] = farm_quantity
|
||||
dependencies[] = farm_quantity_log
|
||||
dependencies[] = farm_report
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Farm livestock weight install.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Install the Farm Report module (dependency of Livestock Weight Report).
|
||||
*/
|
||||
function farm_livestock_weight_update_7000(&$sandbox) {
|
||||
$module = 'farm_report';
|
||||
if (!module_exists($module)) {
|
||||
module_enable(array($module));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
(function ($) {
|
||||
Drupal.behaviors.farm_livestock_weight_graph = {
|
||||
attach: function (context, settings) {
|
||||
|
||||
// Calculate the timezone offset in milliseconds.
|
||||
var tzoffset = (new Date()).getTimezoneOffset() * 60000;
|
||||
|
||||
// Iterate through the graphs.
|
||||
for (var i = 0; i < settings.farm_livestock_report.graphs.length; i++) {
|
||||
|
||||
// Get the graph name, id, and data.
|
||||
var name = settings.farm_livestock_report.graphs[i]['name'];
|
||||
var id = settings.farm_livestock_report.graphs[i]['id'];
|
||||
var data = settings.farm_livestock_report.graphs[i]['data'];
|
||||
|
||||
// Initialize variables.
|
||||
var dates=[];
|
||||
var values=[];
|
||||
|
||||
// Initialize the default_units
|
||||
var default_units = '';
|
||||
|
||||
// Iterate through the data and put it into the arrays.
|
||||
for (var j = 0; j < data.length; j++) {
|
||||
// Set the default units to the first log with recorded units.
|
||||
if (default_units == '') {
|
||||
default_units = data[j].units;
|
||||
}
|
||||
// Exclude weights that have a unit different than the default units.
|
||||
// Accept weights that do not have a unit recorded.
|
||||
if(data[j].units != default_units && data[j].units != '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
var date = new Date((data[j].timestamp * 1000) - tzoffset).toISOString();
|
||||
dates.push(date);
|
||||
values.push(data[j].value);
|
||||
}
|
||||
|
||||
// Assemble variables for plotly.
|
||||
var graph_data=[{
|
||||
x: dates,
|
||||
y: values,
|
||||
name: name,
|
||||
type: 'scatter'
|
||||
}];
|
||||
var layout = {
|
||||
title: name,
|
||||
height: 400,
|
||||
xaxis: { title: 'Date' },
|
||||
yaxis: { title: 'Weight (' + default_units + ')' }
|
||||
};
|
||||
|
||||
// Draw the graph to the element.
|
||||
element = document.getElementById(id);
|
||||
Plotly.newPlot(element, graph_data, layout);
|
||||
}
|
||||
}
|
||||
};
|
||||
}(jQuery));
|
|
@ -88,6 +88,490 @@ function farm_livestock_weight_set($assets, $weight, $units, $timestamp = REQUES
|
|||
return $log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function farm_livestock_weight_menu() {
|
||||
$items = array();
|
||||
|
||||
// Farm asset uri for the view path
|
||||
$farm_asset_uri = 'farm/asset/%farm_asset';
|
||||
$farm_asset_uri_argument_position = 2;
|
||||
|
||||
// Animal asset report tab.
|
||||
$items[$farm_asset_uri . '/weight'] = array(
|
||||
'title' => 'Weight',
|
||||
'page callback' => 'farm_livestock_weight_individual_report',
|
||||
'page arguments' => array($farm_asset_uri_argument_position),
|
||||
'access callback' => 'farm_livestock_weight_individual_report_access',
|
||||
'access arguments' => array($farm_asset_uri_argument_position),
|
||||
'file' => 'farm_livestock_weight.report.inc',
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
|
||||
);
|
||||
|
||||
// Animal group report form.
|
||||
$items['farm/report/weight'] = array(
|
||||
'title' => 'Animal Weights',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('farm_livestock_weight_group_report_form'),
|
||||
'access arguments' => array('view farm reports'),
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
);
|
||||
|
||||
return $items;
|
||||
};
|
||||
|
||||
/**
|
||||
* Individual report view access callback.
|
||||
*
|
||||
* @param $farm_asset
|
||||
* The asset to check access for.
|
||||
*
|
||||
* @return bool
|
||||
* Returns boolean value indicating whether or not access is granted.
|
||||
*/
|
||||
function farm_livestock_weight_individual_report_access($farm_asset) {
|
||||
|
||||
// If the asset is not an animal, deny access.
|
||||
if ($farm_asset->type != 'animal') {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Finally, check to see if the user has access to the asset.
|
||||
return farm_asset_access('view', $farm_asset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Animal group report form.
|
||||
*/
|
||||
function farm_livestock_weight_group_report_form($form, &$form_state) {
|
||||
|
||||
// Set the page title.
|
||||
drupal_set_title('Animal Weights');
|
||||
|
||||
// Build an entity field query of group assets.
|
||||
$query = new EntityFieldQuery();
|
||||
$query->entityCondition('entity_type', 'farm_asset');
|
||||
$query->entityCondition('bundle', 'group');
|
||||
$query->propertyOrderBy('name', 'ASC');
|
||||
|
||||
// Limit to non-archived groups.
|
||||
$query->propertyCondition('archived', 0);
|
||||
|
||||
// Execute the query and build a list of options.
|
||||
$result = $query->execute();
|
||||
if (isset($result['farm_asset'])) {
|
||||
$group_ids = array_keys($result['farm_asset']);
|
||||
$groups = farm_asset_load_multiple($group_ids);
|
||||
if (!empty($groups)) {
|
||||
foreach ($groups as $group) {
|
||||
if (!empty($group->id)) {
|
||||
$options[$group->id] = entity_label('farm_asset', $group);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Define the input fieldset
|
||||
$form['input'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Input Form'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => FALSE,
|
||||
);
|
||||
|
||||
// Create a select field for the groups.
|
||||
$form['input']['group'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Animal Group'),
|
||||
'#description' => t('Select the group(s) of animals to include in the weight report.'),
|
||||
'#options' => $options,
|
||||
'#required' => TRUE,
|
||||
'#multiple' => TRUE,
|
||||
);
|
||||
|
||||
// Provide a default date in the format YYYY-MM-DD.
|
||||
$format = 'Y-m-d';
|
||||
$current_date = date($format, REQUEST_TIME);
|
||||
|
||||
$form['input']['start_date'] = array(
|
||||
'#type' => 'date_select',
|
||||
'#title' => t('Start date'),
|
||||
'#description' => t('First recorded date of animal weights to include..'),
|
||||
'#default_value' => '',
|
||||
'#date_year_range' => '-10:+1',
|
||||
'#date_format' => $format,
|
||||
'#date_label_position' => 'within',
|
||||
);
|
||||
|
||||
$form['input']['end_date'] = array(
|
||||
'#type' => 'date_select',
|
||||
'#title' => t('End date'),
|
||||
'#description' => t('Last recorded date of animal weights to include..'),
|
||||
'#default_value' => $current_date,
|
||||
'#date_year_range' => '-10:+1',
|
||||
'#date_format' => $format,
|
||||
'#date_label_position' => 'within',
|
||||
);
|
||||
|
||||
// Add submit button to generate report.
|
||||
$form['input']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Submit'),
|
||||
'#submit' => array('farm_livestock_weight_group_report_form_submit'),
|
||||
);
|
||||
|
||||
// Add submit button to download CSV.
|
||||
$form['input']['csv'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('CSV'),
|
||||
'#submit' => array('farm_livestock_weight_group_report_csv'),
|
||||
);
|
||||
|
||||
// Display results from the form.
|
||||
if (!empty($form_state['results_table'])) {
|
||||
// Hide the input fieldset
|
||||
$form['input']['#collapsed'] = TRUE;
|
||||
|
||||
// Create a results fieldset.
|
||||
$form['results'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Results'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => FALSE,
|
||||
);
|
||||
|
||||
// Display the Graphs.
|
||||
$graphs = '<div class="farm-livestock-weight-group-report-graphs">' . implode('', $form_state['graph-markup']) . '</div>';
|
||||
|
||||
// Add JS and CSS to build the graphs.
|
||||
drupal_add_js($form_state['graph-settings'], 'setting');
|
||||
drupal_add_js(drupal_get_path('module', 'farm_livestock_weight') . '/farm_livestock_weight_group_graph.js');
|
||||
drupal_add_js('https://cdn.plot.ly/plotly-latest.min.js', 'external');
|
||||
drupal_add_css(drupal_get_path('module', 'farm_livestock_weight') . '/farm_livestock_weight.css');
|
||||
|
||||
$form['results']['graphs'] = array('#markup' => $graphs);
|
||||
|
||||
// Display the HTML Table.
|
||||
$form['results']['results_table'] = array('#markup' => $form_state['results_table']);
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for the weight report form
|
||||
*/
|
||||
function farm_livestock_weight_group_report_form_submit($form, &$form_state) {
|
||||
$results = farm_livestock_weight_group_report($form_state);
|
||||
$form_state['graph-settings'] = $results['graph-settings'];
|
||||
$form_state['graph-markup'] = $results['graph-markup'];
|
||||
$form_state['results_table'] = $results['table'];
|
||||
$form_state['rebuild'] = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Animal Weight Group Report
|
||||
*/
|
||||
function farm_livestock_weight_group_report(&$form_state) {
|
||||
|
||||
// Get the submitted group IDs to include in the report.
|
||||
$group_ids = $form_state['values']['group'];
|
||||
|
||||
// Get the start and end dates.
|
||||
$start_date = strtotime($form_state['values']['start_date']);
|
||||
$end_date = strtotime($form_state['values']['end_date']);
|
||||
|
||||
// Array to store dates of animal weight logs for CSV export.
|
||||
$date_format = 'Y-m-d';
|
||||
$all_log_dates = array();
|
||||
|
||||
// Array to store animals and log data
|
||||
$animals = array();
|
||||
|
||||
// Loop through each group, its members, and all weight logs.
|
||||
foreach ($group_ids as $id) {
|
||||
|
||||
// Load the farm group asset.
|
||||
$group = farm_asset_load($id);
|
||||
$group_name = $group->name;
|
||||
|
||||
// Load the farm group members.
|
||||
$members = farm_group_members($group);
|
||||
|
||||
// Loop through members.
|
||||
foreach ($members as $asset) {
|
||||
|
||||
// If member is not an animal, bail.
|
||||
if ($asset->type != 'animal') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Save the animal info
|
||||
$asset->group = $group;
|
||||
|
||||
// Load the group member's weights
|
||||
$time = REQUEST_TIME;
|
||||
if (!empty($end_date)) {
|
||||
$time = $end_date;
|
||||
}
|
||||
$logs = farm_quantity_log_asset($asset, 'weight', NULL, $time, TRUE, NULL, FALSE);
|
||||
|
||||
// Array to save log dates for this one animal.
|
||||
$log_dates = array();
|
||||
|
||||
// Array to save data from animal logs.
|
||||
$all_log_data = array();
|
||||
|
||||
// Loop through weight logs.
|
||||
foreach ($logs as $log) {
|
||||
// Get the date of the log from the timestamp.
|
||||
$log_date = date($date_format, $log->timestamp);
|
||||
|
||||
// Check that the log timestamp fits the date parameters. Note that we
|
||||
// only need to check the start date bound, because end date is already
|
||||
// filtered by farm_quantity_log_asset().
|
||||
if ($log->timestamp < $start_date) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the log date to the array if not already included.
|
||||
if (!in_array($log_date, $log_dates)){
|
||||
$log_dates[] = $log_date;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Extract quantity data from the log.
|
||||
$data = farm_quantity_log_data($log, 'weight');
|
||||
|
||||
// Iterate through the data and return the first one with a value.
|
||||
foreach ($data as $quantity) {
|
||||
if (!empty($quantity['value'])) {
|
||||
$value = $quantity['value'];
|
||||
$units = $quantity['units'];
|
||||
|
||||
// Add the log data to array of logs.
|
||||
$log_data = array();
|
||||
$log_data['date'] = $log_date;
|
||||
$log_data['value'] = $value;
|
||||
$log_data['units'] = $units;
|
||||
|
||||
$all_log_data[]= $log_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Merge animal's log dates with all_log_dates.
|
||||
$all_log_dates = array_unique( array_merge( $all_log_dates, $log_dates));
|
||||
|
||||
// Save all log data with the animal.
|
||||
$asset->all_log_data = $all_log_data;
|
||||
|
||||
// Add animal data to array of all animals.
|
||||
$animals[] = $asset;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort all collected log_dates.
|
||||
sort($all_log_dates);
|
||||
|
||||
// Create a header for CSV and HTML Table
|
||||
$header = array('AssetID', 'AssetName', 'Group');
|
||||
|
||||
// Add columns for each date collected.
|
||||
foreach ($all_log_dates as $date) {
|
||||
$header[] = 'Date - ' . $date ;
|
||||
$header[] = 'Weight';
|
||||
$header[] = 'Units';
|
||||
}
|
||||
|
||||
// Add the CSV header.
|
||||
$csvdata = implode(',', $header) . PHP_EOL;
|
||||
|
||||
// Initialize array for Date Averages
|
||||
$group_date_averages = array();
|
||||
foreach($group_ids as $id) {
|
||||
$group_date_averages[$id] = array(
|
||||
'group' => farm_asset_load($id),
|
||||
'dates' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($animals as $animal) {
|
||||
// Add a row of data.
|
||||
$row = array();
|
||||
$row[] = $animal->id;
|
||||
$row[] = $animal->name;
|
||||
$row[] = $animal->group->name;
|
||||
|
||||
// Save the logs.
|
||||
$logs = $animal->all_log_data;
|
||||
|
||||
// Skip adding logs if the animal has no logs
|
||||
if (sizeof($logs) == 0) {
|
||||
// Add Animal info to results.
|
||||
$table_data[] = $row;
|
||||
$csvdata .= implode(',', $row) . PHP_EOL;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Sort the logs by date.
|
||||
usort($logs, "farm_livestock_weight_log_array_sort_date");
|
||||
|
||||
// Save a counter for which log to compare.
|
||||
$curr_log_index = 0;
|
||||
|
||||
// Save a counter for which column to compare.
|
||||
$curr_column_index = 0;
|
||||
|
||||
// Walk through each column and add log data if log date == column date.
|
||||
// Note that each date requires 3 columns in the CSV file to display the
|
||||
// date, value and units of recorded log weights.
|
||||
while($curr_log_index < sizeof($logs) && $curr_column_index < sizeof($all_log_dates)) {
|
||||
|
||||
// Conert the dates to times for easier comparison.
|
||||
$column_time = strtotime($all_log_dates[$curr_column_index]);
|
||||
$log_time = strtotime($logs[$curr_log_index]['date']);
|
||||
|
||||
// If the log_time is less than column_time, then there are multiple logs
|
||||
// on the same date for the animal. The first one has already been saved,
|
||||
// skip any additional logs with the same date.
|
||||
if ($column_time > $log_time) {
|
||||
$curr_log_index += 1;
|
||||
|
||||
// Set empty values if the times don't match.
|
||||
// Move to next column
|
||||
} else if ($column_time != $log_time) {
|
||||
$row[] = '';
|
||||
$row[] = '';
|
||||
$row[] = '';
|
||||
$curr_column_index += 1;
|
||||
|
||||
|
||||
} else {
|
||||
$log_date = $logs[$curr_log_index]['date'];
|
||||
$log_value = $logs[$curr_log_index]['value'];
|
||||
$log_units = $logs[$curr_log_index]['units'];
|
||||
|
||||
// Save the log date, value and units if the times match.
|
||||
$row[] = $log_date;
|
||||
$row[] = $log_value;
|
||||
$row[] = $log_units;
|
||||
|
||||
// For displaying graphs of average weights
|
||||
// Tally the weight of the animal in the All Log Dates array
|
||||
|
||||
// Initialize the Group's average weight array for the log date.
|
||||
if (!isset($group_date_averages[$animal->group->id]['dates'][$log_date])) {
|
||||
$group_date_averages[$animal->group->id]['dates'][$log_date] = array(
|
||||
'units' => $log_units,
|
||||
'total_weight' => $log_value,
|
||||
'animal_count' => 1,
|
||||
);
|
||||
} else {
|
||||
$group_date_averages[$animal->group->id]['dates'][$log_date]['total_weight'] += $log_value;
|
||||
$group_date_averages[$animal->group->id]['dates'][$log_date]['animal_count'] += 1;
|
||||
}
|
||||
|
||||
// Move to next column, and next log.
|
||||
$curr_column_index += 1;
|
||||
$curr_log_index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Add row to HTML Table
|
||||
$table_data[] = $row;
|
||||
|
||||
// Add to CSV string
|
||||
$csvdata .= implode(',', $row) . PHP_EOL;
|
||||
}
|
||||
|
||||
// Create HTML Table
|
||||
$table = theme('table', array('header' => $header, 'rows' => $table_data));
|
||||
|
||||
// Create the div to hold report graphs.
|
||||
$graph_markup = array();
|
||||
|
||||
// Create a graph object to pass to JS.
|
||||
$graphs = array();
|
||||
|
||||
// Create graphs for each group
|
||||
foreach($group_date_averages as $group){
|
||||
$group_name = $group['group']->name;
|
||||
|
||||
// Sort the array by date
|
||||
ksort($group['dates']);
|
||||
|
||||
$dates = array_keys($group['dates']);
|
||||
for($i = 0; $i < count($group['dates']); $i++){
|
||||
$date = $dates[$i];
|
||||
|
||||
// Calculate average weight.
|
||||
$date_average = $group['dates'][$date]['total_weight'] / $group['dates'][$date]['animal_count'];
|
||||
$group['dates'][$date]['average_weight'] = $date_average;
|
||||
|
||||
// Calculate Average Daily Gain after the first date.
|
||||
if ($i > 0) {
|
||||
$previous_date = $dates[$i -1];
|
||||
$previous_average = $group['dates'][$previous_date]['average_weight'];
|
||||
|
||||
// Calculate gain between the two dates.
|
||||
$gain = $date_average - $previous_average;
|
||||
|
||||
// Calculate days elapsed.
|
||||
$dStart = new DateTime($previous_date);
|
||||
$dEnd = new DateTime($date);
|
||||
$days_elapsed = (int) $dStart->diff($dEnd)->format("%a");
|
||||
|
||||
// Save the daily gain value within the 'date' array.
|
||||
$group['dates'][$date]['gain'] = $gain / $days_elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
// Create Average Weight Graph
|
||||
$graph = array(
|
||||
'name' => 'Average Weight - ' . $group_name,
|
||||
'id' => 'farm-livestock-average-weight-' . $group_name . '-graph',
|
||||
'data' => $group['dates'],
|
||||
);
|
||||
$graphs[] = $graph;
|
||||
$graph_markup[] = '<div id="farm-livestock-average-weight-' . $group_name . '-graph" class="farm-report-graph"></div>';
|
||||
}
|
||||
|
||||
$graph_settings = array(
|
||||
'farm_livestock_report' => array(
|
||||
'graphs' => $graphs,
|
||||
),
|
||||
);
|
||||
|
||||
return array(
|
||||
'graph-settings' => $graph_settings,
|
||||
'graph-markup' => $graph_markup,
|
||||
'table' => $table,
|
||||
'csv' => $csvdata,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Animal Weight Group Report CSV Export
|
||||
*/
|
||||
function farm_livestock_weight_group_report_csv($form, &$form_state){
|
||||
$results = farm_livestock_weight_group_report($form_state);
|
||||
|
||||
drupal_add_http_header('Content-Type', 'text/csv');
|
||||
drupal_add_http_header('Content-Disposition', 'attachment; filename=animal_weights.csv');
|
||||
print $results['csv'];
|
||||
|
||||
drupal_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to sort an array of logs by timestamp
|
||||
*/
|
||||
function farm_livestock_weight_log_array_sort_date($a, $b) {
|
||||
return strtotime($a['date']) - strtotime($b['date']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_view_alter().
|
||||
|
@ -101,6 +585,7 @@ function farm_livestock_weight_entity_view_alter(&$build, $type) {
|
|||
|
||||
// Alias the asset variable.
|
||||
$asset = $build['#entity'];
|
||||
$asset_uri = entity_uri('farm_asset', $asset);
|
||||
|
||||
// If it isn't an animal asset, bail.
|
||||
if ($asset->type != 'animal') {
|
||||
|
@ -120,7 +605,7 @@ function farm_livestock_weight_entity_view_alter(&$build, $type) {
|
|||
$units = !empty($weight['units']) ? $weight['units'] : '';
|
||||
|
||||
// Build the weight display.
|
||||
$output = '<strong>' . t('Weight') . ':</strong> ' . $value . ' ' . $units;
|
||||
$output = '<strong>' . t('Weight') . ':</strong> ' . $value . ' ' . $units . '<a href="' . url($asset_uri['path'] . '/weight') . '"> (weight report) </a>';
|
||||
|
||||
// If the animal has an inventory greater than 1, add "(average)".
|
||||
$inventory = farm_inventory($asset);
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Farm livestock report page.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Asset Report view callback.
|
||||
*
|
||||
* @param FarmAsset $farm_asset
|
||||
* The farm asset entity.
|
||||
*
|
||||
* @return
|
||||
* Returns the page content.
|
||||
*/
|
||||
function farm_livestock_weight_individual_report(FarmAsset $farm_asset) {
|
||||
$output = '';
|
||||
|
||||
// Get the assets current weight.
|
||||
$current_weight = farm_livestock_weight($farm_asset);
|
||||
|
||||
// Check if the asset has a weight recorded.
|
||||
if (empty($current_weight)) {
|
||||
$output .= '<p>No weight recorded for asset</p>';
|
||||
} else {
|
||||
$output .= '<p><strong>Current Weight:</strong> ' . $current_weight['value'] . ' ' . $current_weight['units'] . '</p>';
|
||||
};
|
||||
|
||||
// Get all 'weight' logs associated with the asset.
|
||||
$logs = farm_quantity_log_asset($farm_asset, 'weight', $label = NULL, $time = REQUEST_TIME, $done = TRUE, $type = NULL, $single = FALSE);
|
||||
|
||||
// Store all log weight data
|
||||
$log_weights = array();
|
||||
|
||||
// Ensure there are weight logs.
|
||||
if (!empty($logs)) {
|
||||
// Simple html table of weights.
|
||||
$output .= '<h3> All Weights </h3>';
|
||||
$header = array('Date', 'Value', 'Units');
|
||||
$table_data = array();
|
||||
|
||||
foreach ($logs as $log) {
|
||||
// Extract quantity data from the log.
|
||||
$data = farm_quantity_log_data($log, 'weight');
|
||||
|
||||
// Iterate through the data and return the first one with a value.
|
||||
foreach ($data as $quantity) {
|
||||
if (!empty($quantity['value'])) {
|
||||
$value = $quantity['value'];
|
||||
$units = $quantity['units'];
|
||||
|
||||
// Save the timestamp with data for the graph.
|
||||
$quantity['timestamp'] = $log->timestamp;
|
||||
|
||||
// Add to $log_weights array.
|
||||
$log_weights[] = $quantity;
|
||||
$table_data[] = array(format_date($log->timestamp), $value, $units);
|
||||
}
|
||||
}
|
||||
}
|
||||
$output .= theme('table', array('header' => $header, 'rows' => $table_data));
|
||||
|
||||
// Create the div to hold report graphs.
|
||||
$graph_markup = array();
|
||||
|
||||
// Create a graph object to pass to JS.
|
||||
$graphs = array();
|
||||
|
||||
// Create a Weight Report Graph
|
||||
$graph = array(
|
||||
'name' => $farm_asset->name . ' Weight Report',
|
||||
'id' => 'farm-report-weight-graph',
|
||||
'data' => $log_weights,
|
||||
);
|
||||
$graph_markup[] = '<div id="farm-report-weight-graph" class="farm-report-graph"></div>';
|
||||
$graphs[] = $graph;
|
||||
|
||||
$settings = array(
|
||||
'farm_livestock_report' => array(
|
||||
'graphs' => $graphs,
|
||||
),
|
||||
);
|
||||
|
||||
// Add graphs to output.
|
||||
$output = '<div class="farm-report-graphs">' . implode('', $graph_markup) . '</div>' . $output;
|
||||
|
||||
// Add JS and CSS to build the graphs.
|
||||
drupal_add_js($settings, 'setting');
|
||||
drupal_add_js(drupal_get_path('module', 'farm_livestock_weight') . '/farm_livestock_weight.js');
|
||||
drupal_add_js('https://cdn.plot.ly/plotly-latest.min.js', 'external');
|
||||
drupal_add_css(drupal_get_path('module', 'farm_livestock_weight') . '/farm_livestock_weight.css');
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
(function ($) {
|
||||
Drupal.behaviors.farm_livestock_weight_graph = {
|
||||
attach: function (context, settings) {
|
||||
|
||||
// Calculate the timezone offset in milliseconds.
|
||||
var tzoffset = (new Date()).getTimezoneOffset() * 60000;
|
||||
|
||||
// Iterate through the graphs.
|
||||
for (var i = 0; i < settings.farm_livestock_report.graphs.length; i++) {
|
||||
|
||||
// Get the graph name, id, and data.
|
||||
var name = settings.farm_livestock_report.graphs[i]['name'];
|
||||
var id = settings.farm_livestock_report.graphs[i]['id'];
|
||||
var data = settings.farm_livestock_report.graphs[i]['data'];
|
||||
|
||||
// Initialize variables.
|
||||
var average_dates=[];
|
||||
var average_values=[];
|
||||
var average_value_text=[];
|
||||
|
||||
var gain_dates=[];
|
||||
var gain_values=[];
|
||||
|
||||
// Initialize the default_units
|
||||
var default_units = '';
|
||||
|
||||
// Iterate through the data and put it into the arrays.
|
||||
for (var d in data) {
|
||||
if (default_units == '') {
|
||||
default_units = data[d].units;
|
||||
}
|
||||
var date = new Date(d).toISOString();
|
||||
average_dates.push(date);
|
||||
average_values.push(data[d].average_weight);
|
||||
average_value_text.push(data[d].animal_count + " animals weighed");
|
||||
|
||||
if (data[d].hasOwnProperty('gain')) {
|
||||
gain_dates.push(date);
|
||||
gain_values.push(data[d].gain);
|
||||
}
|
||||
}
|
||||
|
||||
// Assemble variables for plotly.
|
||||
var average_data={
|
||||
x: average_dates,
|
||||
y: average_values,
|
||||
text: average_value_text,
|
||||
name: 'Average Weight',
|
||||
type: 'scatter'
|
||||
};
|
||||
|
||||
var gain_data={
|
||||
x: gain_dates,
|
||||
y: gain_values,
|
||||
yaxis: 'y2',
|
||||
name: 'Average Daily Gain',
|
||||
type: 'scatter'
|
||||
};
|
||||
|
||||
var all_data = [average_data, gain_data];
|
||||
|
||||
var layout = {
|
||||
title: name,
|
||||
height: 400,
|
||||
xaxis: { title: 'Date' },
|
||||
yaxis: { title: 'Average Weight (' + default_units + ')' },
|
||||
yaxis2: {
|
||||
title: 'Average Daily Gain (' + default_units + ')',
|
||||
overlaying: 'y',
|
||||
side: 'right'
|
||||
}
|
||||
};
|
||||
|
||||
// Draw the graph to the element.
|
||||
element = document.getElementById(id);
|
||||
Plotly.newPlot(element, all_data, layout);
|
||||
}
|
||||
}
|
||||
};
|
||||
}(jQuery));
|
|
@ -74,7 +74,7 @@ function farm_quantity_log_data(Log $log, $measure = NULL, $label = NULL) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Load an asset's latest log with a given quantity measure and/or label.
|
||||
* Load logs for an asset with a given quantity measure and/or label.
|
||||
*
|
||||
* @param FarmAsset $asset
|
||||
* The farm_asset object to look for.
|
||||
|
@ -89,11 +89,15 @@ function farm_quantity_log_data(Log $log, $measure = NULL, $label = NULL) {
|
|||
* Whether or not to only show logs that are marked as "done". TRUE will limit
|
||||
* to logs that are done, and FALSE will limit to logs that are not done. If
|
||||
* this is set to NULL, no filtering will be applied. Defaults to TRUE.
|
||||
* @param string $type
|
||||
* The log type to filter by. If empty, no filtering will be applied.
|
||||
* @param bool $single
|
||||
* Whether or not to limit the query to a single result. Defaults to TRUE.
|
||||
*
|
||||
* @return Log|bool
|
||||
* Returns a log entity. FALSE if something goes wrong.
|
||||
* @return Log|array|bool
|
||||
* Returns a log entity, or an array of them. FALSE if something goes wrong.
|
||||
*/
|
||||
function farm_quantity_log_asset(FarmAsset $asset, $measure = NULL, $label = NULL, $time = REQUEST_TIME, $done = TRUE) {
|
||||
function farm_quantity_log_asset(FarmAsset $asset, $measure = NULL, $label = NULL, $time = REQUEST_TIME, $done = TRUE, $type = NULL, $single = TRUE) {
|
||||
|
||||
// If the asset doesn't have an ID (for instance if it is new and hasn't been
|
||||
// saved yet), bail.
|
||||
|
@ -102,21 +106,34 @@ function farm_quantity_log_asset(FarmAsset $asset, $measure = NULL, $label = NUL
|
|||
}
|
||||
|
||||
// Make a query for loading the latest quantity log.
|
||||
$query = farm_quantity_log_asset_query($asset->id, $measure, $label, $time, $done);
|
||||
$query = farm_quantity_log_asset_query($asset->id, $measure, $label, $time, $done, $type, $single);
|
||||
|
||||
// Execute the query and gather the log id.
|
||||
$result = $query->execute();
|
||||
$log_id = $result->fetchField();
|
||||
|
||||
// If a log id exists, load and return it.
|
||||
// Return array of log objects. $single = FALSE
|
||||
if (empty($single)) {
|
||||
$log_item_ids = $result->fetchCol();
|
||||
$logs = entity_load('log', $log_item_ids);
|
||||
return $logs;
|
||||
}
|
||||
|
||||
// Return one log object. $single = TRUE
|
||||
else {
|
||||
if (!empty($single)) {
|
||||
$log_id = $result->fetchField();
|
||||
if (!empty($log_id)) {
|
||||
return log_load($log_id);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// If all else fails, return FALSE.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a query to find the latest log of an asset that defines a quantity.
|
||||
* Build a query to find logs of an asset that defines a quantity.
|
||||
*
|
||||
* @param int $asset_id
|
||||
* The asset id to search for.
|
||||
|
@ -127,15 +144,19 @@ function farm_quantity_log_asset(FarmAsset $asset, $measure = NULL, $label = NUL
|
|||
* @param int $time
|
||||
* Unix timestamp limiter. Only logs before this time will be included.
|
||||
* Defaults to the current time. Set to 0 to load the absolute last.
|
||||
* @param $done
|
||||
* @param bool|null $done
|
||||
* Whether or not to only show logs that are marked as "done". TRUE will limit
|
||||
* to logs that are done, and FALSE will limit to logs that are not done. If
|
||||
* any other value is used, no filtering will be applied. Defaults to TRUE.
|
||||
* this is set to NULL, no filtering will be applied. Defaults to TRUE.
|
||||
* @param string|null $type
|
||||
* The log type to filter by. If this is NULL, no filtering will be applied.
|
||||
* @param bool $single
|
||||
* Whether or not to limit the query to a single result. Defaults to TRUE.
|
||||
*
|
||||
* @return \SelectQuery
|
||||
* Returns a SelectQuery object.
|
||||
*/
|
||||
function farm_quantity_log_asset_query($asset_id, $measure = NULL, $label = NULL, $time = REQUEST_TIME, $done = TRUE) {
|
||||
function farm_quantity_log_asset_query($asset_id, $measure = NULL, $label = NULL, $time = REQUEST_TIME, $done = TRUE, $type = NULL, $single = TRUE) {
|
||||
|
||||
/**
|
||||
* Please read the comments in farm_log_asset_query() to understand how this
|
||||
|
@ -144,7 +165,7 @@ function farm_quantity_log_asset_query($asset_id, $measure = NULL, $label = NULL
|
|||
*/
|
||||
|
||||
// Use the farm_log_asset_query() helper function to start a query object.
|
||||
$query = farm_log_asset_query($asset_id, $time, $done);
|
||||
$query = farm_log_asset_query($asset_id, $time, $done, $type, $single);
|
||||
|
||||
// Add a query tag to identify where this came from.
|
||||
$query->addTag('farm_quantity_log_asset_query');
|
||||
|
|
|
@ -6,6 +6,7 @@ dependencies[] = ctools
|
|||
dependencies[] = farm_asset
|
||||
dependencies[] = farm_log
|
||||
dependencies[] = farm_quantity
|
||||
dependencies[] = farm_report
|
||||
dependencies[] = views
|
||||
dependencies[] = views_data_export
|
||||
features[ctools][] = views:views_default:3.0
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Farm quantity report install.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Install the Farm Report module (dependency of Quantity Report).
|
||||
*/
|
||||
function farm_quantity_report_update_7000(&$sandbox) {
|
||||
$module = 'farm_report';
|
||||
if (!module_exists($module)) {
|
||||
module_enable(array($module));
|
||||
}
|
||||
}
|
|
@ -456,7 +456,7 @@ function farm_quantity_report_views_default_views() {
|
|||
|
||||
/* Display: Page */
|
||||
$handler = $view->new_display('page', 'Page', 'page');
|
||||
$handler->display->display_options['path'] = 'farm/quantity';
|
||||
$handler->display->display_options['path'] = 'farm/report/quantity';
|
||||
$handler->display->display_options['menu']['type'] = 'tab';
|
||||
$handler->display->display_options['menu']['title'] = 'Quantity';
|
||||
$handler->display->display_options['menu']['weight'] = '0';
|
||||
|
|
4
modules/farm/farm_report/farm_report.info
Normal file
4
modules/farm/farm_report/farm_report.info
Normal file
|
@ -0,0 +1,4 @@
|
|||
name = Farm Report
|
||||
description = Features for viewing reports.
|
||||
core = 7.x
|
||||
package = farmOS
|
64
modules/farm/farm_report/farm_report.module
Normal file
64
modules/farm/farm_report/farm_report.module
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Farm report module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_permission().
|
||||
*/
|
||||
function farm_report_permission() {
|
||||
return array(
|
||||
'view farm reports' => array(
|
||||
'title' => t('View farm reports'),
|
||||
),
|
||||
'configure farm reports' => array(
|
||||
'title' => t('Configure farm reports'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_farm_access_perms().
|
||||
*/
|
||||
function farm_report_farm_access_perms($role) {
|
||||
$perms = array();
|
||||
|
||||
// Add the "view farm reports" permission to all roles.
|
||||
$perms[] = 'view farm reports';
|
||||
|
||||
// Load the list of farm roles.
|
||||
$roles = farm_access_roles();
|
||||
|
||||
// If this role has 'config' access, allow them to configure farm reports.
|
||||
if (!empty($roles[$role]['access']['config'])) {
|
||||
$perms[] = 'configure farm reports';
|
||||
}
|
||||
|
||||
return $perms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function farm_report_menu() {
|
||||
$items = array();
|
||||
|
||||
$items['farm/report'] = array(
|
||||
'title' => 'Reports',
|
||||
'page callback' => 'farm_report_view',
|
||||
'access arguments' => array('view farm reports'),
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
);
|
||||
$items['farm/report/info'] = array(
|
||||
'title' => 'Info',
|
||||
'type' => MENU_DEFAULT_LOCAL_TASK,
|
||||
'weight' => -100,
|
||||
);
|
||||
|
||||
return $items;
|
||||
};
|
||||
|
||||
function farm_report_view() {
|
||||
return t('Select a report from the menu above.');
|
||||
};
|
Loading…
Reference in a new issue