First commit
This commit is contained in:
commit
c6e2478c40
13918 changed files with 2303184 additions and 0 deletions
246
sites/all/modules/civicrm/CRM/Case/Audit/Audit.php
Normal file
246
sites/all/modules/civicrm/CRM/Case/Audit/Audit.php
Normal file
|
@ -0,0 +1,246 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class CRM_Case_Audit_Audit
|
||||
*/
|
||||
class CRM_Case_Audit_Audit {
|
||||
private $auditConfig;
|
||||
private $xmlString;
|
||||
|
||||
/**
|
||||
* @param $xmlString
|
||||
* @param string $confFilename
|
||||
*/
|
||||
public function __construct($xmlString, $confFilename) {
|
||||
$this->xmlString = $xmlString;
|
||||
$this->auditConfig = new CRM_Case_Audit_AuditConfig($confFilename);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $printReport
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getActivities($printReport = FALSE) {
|
||||
$retval = array();
|
||||
|
||||
/*
|
||||
* Loop through the activities in the file and add them to the appropriate region array.
|
||||
*/
|
||||
|
||||
$doc = new DOMDocument();
|
||||
|
||||
if ($doc->loadXML($this->xmlString)) {
|
||||
$regionList = $this->auditConfig->getRegions();
|
||||
|
||||
$ifBlanks = $this->auditConfig->getIfBlanks();
|
||||
|
||||
$includeAll = $doc->getElementsByTagName("IncludeActivities")->item(0)->nodeValue;
|
||||
$includeAll = ($includeAll == 'All');
|
||||
|
||||
$activityindex = 0;
|
||||
$activityList = $doc->getElementsByTagName("Activity");
|
||||
|
||||
$caseActivities = array();
|
||||
$activityStatusType = array();
|
||||
|
||||
foreach ($activityList as $activity) {
|
||||
$retval[$activityindex] = array();
|
||||
|
||||
$ifBlankReplacements = array();
|
||||
|
||||
$completed = FALSE;
|
||||
$sortValues = array('1970-01-01');
|
||||
$category = '';
|
||||
$fieldindex = 1;
|
||||
$fields = $activity->getElementsByTagName("Field");
|
||||
foreach ($fields as $field) {
|
||||
$datatype_elements = $field->getElementsByTagName("Type");
|
||||
$datatype = $datatype_elements->item(0)->nodeValue;
|
||||
|
||||
$label_elements = $field->getElementsByTagName("Label");
|
||||
$label = $label_elements->item(0)->nodeValue;
|
||||
|
||||
$value_elements = $field->getElementsByTagName("Value");
|
||||
$value = $value_elements->item(0)->nodeValue;
|
||||
|
||||
$category_elements = $field->getElementsByTagName("Category");
|
||||
if (!empty($category_elements->length)) {
|
||||
$category = $category_elements->item(0)->nodeValue;
|
||||
}
|
||||
|
||||
// Based on the config file, does this field's label and value indicate a completed activity?
|
||||
if ($label == $this->auditConfig->getCompletionLabel() && $value == $this->auditConfig->getCompletionValue()) {
|
||||
$completed = TRUE;
|
||||
}
|
||||
|
||||
// Based on the config file, does this field's label match the one to use for sorting activities?
|
||||
if (in_array($label, $this->auditConfig->getSortByLabels())) {
|
||||
$sortValues[$label] = $value;
|
||||
}
|
||||
|
||||
foreach ($regionList as $region) {
|
||||
// Based on the config file, is this field a potential replacement for another?
|
||||
if (!empty($ifBlanks[$region])) {
|
||||
if (in_array($label, $ifBlanks[$region])) {
|
||||
$ifBlankReplacements[$label] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->auditConfig->includeInRegion($label, $region)) {
|
||||
$retval[$activityindex][$region][$fieldindex] = array();
|
||||
$retval[$activityindex][$region][$fieldindex]['label'] = $label;
|
||||
$retval[$activityindex][$region][$fieldindex]['datatype'] = $datatype;
|
||||
$retval[$activityindex][$region][$fieldindex]['value'] = $value;
|
||||
if ($datatype == 'Date') {
|
||||
$retval[$activityindex][$region][$fieldindex]['includeTime'] = $this->auditConfig->includeTime($label, $region);
|
||||
}
|
||||
|
||||
//CRM-4570
|
||||
if ($printReport) {
|
||||
if (!in_array($label, array(
|
||||
'Activity Type',
|
||||
'Status',
|
||||
))
|
||||
) {
|
||||
$caseActivities[$activityindex][$fieldindex] = array();
|
||||
$caseActivities[$activityindex][$fieldindex]['label'] = $label;
|
||||
$caseActivities[$activityindex][$fieldindex]['datatype'] = $datatype;
|
||||
$caseActivities[$activityindex][$fieldindex]['value'] = $value;
|
||||
}
|
||||
else {
|
||||
$activityStatusType[$activityindex][$fieldindex] = array();
|
||||
$activityStatusType[$activityindex][$fieldindex]['label'] = $label;
|
||||
$activityStatusType[$activityindex][$fieldindex]['datatype'] = $datatype;
|
||||
$activityStatusType[$activityindex][$fieldindex]['value'] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$fieldindex++;
|
||||
}
|
||||
|
||||
if ($printReport) {
|
||||
$caseActivities[$activityindex] = CRM_Utils_Array::crmArrayMerge($activityStatusType[$activityindex], $caseActivities[$activityindex]);
|
||||
$caseActivities[$activityindex]['sortValues'] = $sortValues;
|
||||
}
|
||||
|
||||
if ($includeAll || !$completed) {
|
||||
$retval[$activityindex]['completed'] = $completed;
|
||||
$retval[$activityindex]['category'] = $category;
|
||||
$retval[$activityindex]['sortValues'] = $sortValues;
|
||||
|
||||
// Now sort the fields based on the order in the config file.
|
||||
foreach ($regionList as $region) {
|
||||
$this->auditConfig->sort($retval[$activityindex][$region], $region);
|
||||
}
|
||||
|
||||
$retval[$activityindex]['editurl'] = $activity->getElementsByTagName("EditURL")->item(0)->nodeValue;
|
||||
|
||||
// If there are any fields with ifBlank specified, replace their values.
|
||||
// We need to do this as a second pass because if we do it while looping through fields we might not have come across the field we need yet.
|
||||
foreach ($regionList as $region) {
|
||||
foreach ($retval[$activityindex][$region] as & $v) {
|
||||
$vlabel = $v['label'];
|
||||
if (trim($v['value']) == '' && !empty($ifBlanks[$region][$vlabel])) {
|
||||
if (!empty($ifBlankReplacements[$ifBlanks[$region][$vlabel]])) {
|
||||
$v['value'] = $ifBlankReplacements[$ifBlanks[$region][$vlabel]];
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($v);
|
||||
}
|
||||
|
||||
$activityindex++;
|
||||
}
|
||||
else {
|
||||
/* This is a little bit inefficient, but the alternative is to do two passes
|
||||
because we don't know until we've examined all the field values whether the activity
|
||||
is completed, since the field that determines it and its value is configurable,
|
||||
so either way isn't ideal. */
|
||||
|
||||
unset($retval[$activityindex]);
|
||||
unset($caseActivities[$activityindex]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($printReport) {
|
||||
@uasort($caseActivities, array($this, "compareActivities"));
|
||||
}
|
||||
else {
|
||||
@uasort($retval, array($this, "compareActivities"));
|
||||
}
|
||||
}
|
||||
|
||||
if ($printReport) {
|
||||
return $caseActivities;
|
||||
}
|
||||
else {
|
||||
return $retval;
|
||||
}
|
||||
}
|
||||
|
||||
/* compareActivities
|
||||
*
|
||||
* This is intended to be called as a sort callback function, returning whether an activity's date is earlier or later than another's.
|
||||
* The type of date to use is specified in the config.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param $a
|
||||
* @param $b
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function compareActivities($a, $b) {
|
||||
// This should work
|
||||
foreach ($this->auditConfig->getSortByLabels() as $label) {
|
||||
$aval .= empty($a['sortValues']) ? "" : (empty($a['sortValues'][$label]) ? "" : $a['sortValues'][$label]);
|
||||
$bval .= empty($b['sortValues']) ? "" : (empty($b['sortValues'][$label]) ? "" : $b['sortValues'][$label]);
|
||||
}
|
||||
|
||||
if ($aval < $bval) {
|
||||
return -1;
|
||||
}
|
||||
elseif ($aval > $bval) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $xmlString
|
||||
* @param int $clientID
|
||||
* @param int $caseID
|
||||
* @param bool $printReport
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function run($xmlString, $clientID, $caseID, $printReport = FALSE) {
|
||||
/*
|
||||
$fh = fopen('C:/temp/audit2.xml', 'w');
|
||||
fwrite($fh, $xmlString);
|
||||
fclose($fh);
|
||||
*/
|
||||
|
||||
$audit = new CRM_Case_Audit_Audit($xmlString, 'audit.conf.xml');
|
||||
$activities = $audit->getActivities($printReport);
|
||||
|
||||
$template = CRM_Core_Smarty::singleton();
|
||||
$template->assign_by_ref('activities', $activities);
|
||||
|
||||
if ($printReport) {
|
||||
$reportDate = CRM_Utils_Date::customFormat(date('Y-m-d H:i'));
|
||||
$template->assign('reportDate', $reportDate);
|
||||
$contents = $template->fetch('CRM/Case/Audit/Report.tpl');
|
||||
}
|
||||
else {
|
||||
$contents = $template->fetch('CRM/Case/Audit/Audit.tpl');
|
||||
}
|
||||
return $contents;
|
||||
}
|
||||
|
||||
}
|
259
sites/all/modules/civicrm/CRM/Case/Audit/AuditConfig.php
Normal file
259
sites/all/modules/civicrm/CRM/Case/Audit/AuditConfig.php
Normal file
|
@ -0,0 +1,259 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class CRM_Case_Audit_AuditConfig
|
||||
*/
|
||||
class CRM_Case_Audit_AuditConfig {
|
||||
private $filename;
|
||||
private $completionLabel;
|
||||
private $completionValue;
|
||||
private $sortByLabels;
|
||||
private $regionFieldList;
|
||||
private $includeRules;
|
||||
private $sortRegion;
|
||||
private $ifBlanks;
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
*/
|
||||
public function __construct($filename) {
|
||||
$this->filename = $filename;
|
||||
|
||||
// set some defaults
|
||||
$this->completionLabel = "Status";
|
||||
$this->completionValue = "Completed";
|
||||
$this->sortByLabels = array("Actual Date", "Due Date");
|
||||
$this->ifBlanks = array();
|
||||
|
||||
$this->loadConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCompletionValue() {
|
||||
return $this->completionValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCompletionLabel() {
|
||||
return $this->completionLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getSortByLabels() {
|
||||
return $this->sortByLabels;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getIfBlanks() {
|
||||
return $this->ifBlanks;
|
||||
}
|
||||
|
||||
public function loadConfig() {
|
||||
$this->regionFieldList = array();
|
||||
$this->includeRules = array();
|
||||
|
||||
$doc = new DOMDocument();
|
||||
$xmlString = file_get_contents(dirname(__FILE__) . '/' . $this->filename);
|
||||
$load = $doc->loadXML($xmlString);
|
||||
if ($load) {
|
||||
$regions = $doc->getElementsByTagName("region");
|
||||
foreach ($regions as $region) {
|
||||
$regionName = $region->getAttribute("name");
|
||||
$this->regionFieldList[$regionName] = array();
|
||||
|
||||
// Inclusion/exclusion settings
|
||||
$includeRule = $region->getAttribute("includeRule");
|
||||
if (empty($includeRule)) {
|
||||
$includeRule = 'include';
|
||||
}
|
||||
$this->includeRules[$regionName] = array('rule' => $includeRule);
|
||||
if ($includeRule == 'exclude') {
|
||||
$altRegion = $region->getAttribute("exclusionCorrespondingRegion");
|
||||
$this->includeRules[$regionName]['altRegion'] = $altRegion;
|
||||
}
|
||||
|
||||
// Time component display settings
|
||||
$includeTime = $region->getAttribute("includeTime");
|
||||
if (empty($includeTime)) {
|
||||
$includeTime = 'false';
|
||||
}
|
||||
$this->includeRules[$regionName]['includeTime'] = $includeTime;
|
||||
|
||||
$fieldCount = 0;
|
||||
$fields = $region->getElementsByTagName("field");
|
||||
foreach ($fields as $field) {
|
||||
/* Storing them this way, which is backwards to how you might normally
|
||||
have arrays with a numeric key and a text value, ends up making things better
|
||||
in the other functions, in particular the sorting and also inRegion should end
|
||||
up being more efficient (searching for a key instead of a value). */
|
||||
|
||||
$this->regionFieldList[$regionName][$field->nodeValue] = $fieldCount;
|
||||
|
||||
// Field-level overrides of time component display settings
|
||||
$includeTime = $field->getAttribute("includeTime");
|
||||
if (!empty($includeTime)) {
|
||||
$this->regionFieldList[$regionName][$field->nodeValue]['includeTime'] = $includeTime;
|
||||
}
|
||||
|
||||
// ifBlank attribute
|
||||
$ifBlank = $field->getAttribute("ifBlank");
|
||||
if (!empty($ifBlank)) {
|
||||
$this->ifBlanks[$regionName][$field->nodeValue] = $ifBlank;
|
||||
}
|
||||
|
||||
$fieldCount++;
|
||||
}
|
||||
}
|
||||
|
||||
$completionStatus = $doc->getElementsByTagName("completionStatus");
|
||||
if (!empty($completionStatus)) {
|
||||
$label_elements = $completionStatus->item(0)->getElementsByTagName("label");
|
||||
$this->completionLabel = $label_elements->item(0)->nodeValue;
|
||||
|
||||
$value_elements = $completionStatus->item(0)->getElementsByTagName("value");
|
||||
$this->completionValue = $value_elements->item(0)->nodeValue;
|
||||
}
|
||||
|
||||
$sortElement = $doc->getElementsByTagName("sortByLabels");
|
||||
if (!empty($sortElement)) {
|
||||
$this->sortByLabels = array();
|
||||
$label_elements = $sortElement->item(0)->getElementsByTagName("label");
|
||||
foreach ($label_elements as $ele) {
|
||||
$this->sortByLabels[] = $ele->nodeValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if label $n is explicitly listed in region $r in the config.
|
||||
*
|
||||
* @param $n
|
||||
* @param $r
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function inRegion($n, $r) {
|
||||
if (empty($this->regionFieldList[$r])) {
|
||||
return FALSE;
|
||||
}
|
||||
else {
|
||||
return array_key_exists($n, $this->regionFieldList[$r]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Should field $n be included in region $r, taking into account exclusion rules.
|
||||
*
|
||||
* @param $n
|
||||
* @param $r
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function includeInRegion($n, $r) {
|
||||
$add_it = FALSE;
|
||||
$rules = $this->includeRules[$r];
|
||||
if ($rules['rule'] == 'exclude') {
|
||||
if (!$this->inRegion($n, $r) && !$this->inRegion($n, $rules['altRegion'])) {
|
||||
$add_it = TRUE;
|
||||
}
|
||||
}
|
||||
elseif ($this->inRegion($n, $r)) {
|
||||
$add_it = TRUE;
|
||||
}
|
||||
return $add_it;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the time component of field $n in region $r be displayed?
|
||||
*
|
||||
* @param $n
|
||||
* @param $r
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function includeTime($n, $r) {
|
||||
$retval = FALSE;
|
||||
if (empty($this->regionFieldList[$r][$n]['includeTime'])) {
|
||||
// No field-level override, so look at the region's settings
|
||||
if (!empty($this->includeRules[$r]['includeTime'])) {
|
||||
$retval = $this->includeRules[$r]['includeTime'];
|
||||
}
|
||||
}
|
||||
else {
|
||||
$retval = $this->regionFieldList[$r][$n]['includeTime'];
|
||||
}
|
||||
|
||||
// There's a mix of strings and boolean, so convert any strings.
|
||||
if ($retval == 'false') {
|
||||
$retval = FALSE;
|
||||
}
|
||||
elseif ($retval == 'true') {
|
||||
$retval = TRUE;
|
||||
}
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of all the regions in the config file.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getRegions() {
|
||||
return array_keys($this->regionFieldList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort a group of fields for a given region according to the order in the config.
|
||||
* The array to be sorted should have elements that have a member with a key of 'label', and the value should be the field label.
|
||||
*
|
||||
* @param $f
|
||||
* @param $r
|
||||
*/
|
||||
public function sort(&$f, $r) {
|
||||
// For exclusion-type regions, there's nothing to do, because we won't have been given any ordering.
|
||||
if ($this->includeRules[$r]['rule'] == 'exclude') {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sortRegion = $r;
|
||||
uasort($f, array(&$this, "compareFields"));
|
||||
}
|
||||
|
||||
/**
|
||||
* This is intended to be called as a sort callback function, returning whether a field in a region comes before or after another one.
|
||||
* See also PHP's usort().
|
||||
*
|
||||
* @param $a
|
||||
* @param $b
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function compareFields($a, $b) {
|
||||
if (empty($this->regionFieldList[$this->sortRegion][$a['label']])) {
|
||||
$x = 0;
|
||||
}
|
||||
else {
|
||||
$x = $this->regionFieldList[$this->sortRegion][$a['label']];
|
||||
}
|
||||
|
||||
if (empty($this->regionFieldList[$this->sortRegion][$b['label']])) {
|
||||
$y = 0;
|
||||
}
|
||||
else {
|
||||
$y = $this->regionFieldList[$this->sortRegion][$b['label']];
|
||||
}
|
||||
|
||||
return $x - $y;
|
||||
}
|
||||
|
||||
}
|
60
sites/all/modules/civicrm/CRM/Case/Audit/audit.conf.xml
Normal file
60
sites/all/modules/civicrm/CRM/Case/Audit/audit.conf.xml
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
includeRule can be "include" or "exclude".
|
||||
include means include the fields listed in the region.
|
||||
exclude means include all fields not listed in the region AND not listed in the exclusionCorrespondingRegion.
|
||||
|
||||
includeTime is true or false and says whether to include the time component of date fields.
|
||||
It can be overridden at the Field level.
|
||||
|
||||
ifBlank specifies an alternate field to display if the field is blank.
|
||||
-->
|
||||
|
||||
<regions>
|
||||
<region name="leftpane" includeRule="include" includeTime="false">
|
||||
<fields>
|
||||
<field ifBlank="Due Date">Actual Date</field>
|
||||
<field ifBlank="Activity Type">Subject</field>
|
||||
</fields>
|
||||
</region>
|
||||
|
||||
<region name="rightpaneheader" includeRule="include" includeTime="true">
|
||||
<fields>
|
||||
<field>Activity Type</field>
|
||||
<field>Subject</field>
|
||||
<field>Actual Date</field>
|
||||
<field>Created By</field>
|
||||
<field>Revision</field>
|
||||
</fields>
|
||||
</region>
|
||||
|
||||
<!-- The rightpane body then gets "everything that isn't in the header", EXCEPT
|
||||
the fields you specify here. This seems a good compromise
|
||||
over explicitly having to define which fields we want for each activity type,
|
||||
given that they are custom.
|
||||
|
||||
One future tweak is to improve the way the fields get ordered here. Right now
|
||||
they'll just come out the same order as in the export, which will likely be semi-random.
|
||||
-->
|
||||
<region name="rightpanebody" includeRule="exclude" exclusionCorrespondingRegion="rightpaneheader" includeTime="true">
|
||||
<fields>
|
||||
<field>Some field nobody likes</field>
|
||||
</fields>
|
||||
</region>
|
||||
|
||||
<!-- Haven't decided if this one belongs in here. Probably belongs in yet another config file.
|
||||
This tells us which field has the semantic meaning of "status", and which value indicates "completed".
|
||||
-->
|
||||
<completionStatus>
|
||||
<label>Status</label>
|
||||
<value>Completed</value>
|
||||
</completionStatus>
|
||||
<!-- Similarly this probably doesn't belong in here. This tells what field(s) to sort by.
|
||||
-->
|
||||
<sortByLabels>
|
||||
<label>Actual Date</label> <!-- Sort by this first -->
|
||||
<label>Due Date</label> <!-- Then if equal sort by this -->
|
||||
<label>Date and Time</label>
|
||||
</sortByLabels>
|
||||
|
||||
</regions>
|
Loading…
Add table
Add a link
Reference in a new issue