First commit
This commit is contained in:
commit
c6e2478c40
13918 changed files with 2303184 additions and 0 deletions
228
sites/all/modules/civicrm/Civi/CCase/Analyzer.php
Normal file
228
sites/all/modules/civicrm/Civi/CCase/Analyzer.php
Normal file
|
@ -0,0 +1,228 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM 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 Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
namespace Civi\CCase;
|
||||
|
||||
/**
|
||||
* Class Analyzer
|
||||
*
|
||||
* @package Civi\CCase
|
||||
*/
|
||||
class Analyzer {
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $caseId;
|
||||
|
||||
/**
|
||||
* @var array per APIv3
|
||||
*/
|
||||
private $case;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $caseType;
|
||||
|
||||
/**
|
||||
* @var array per APIv3
|
||||
*/
|
||||
private $activities;
|
||||
|
||||
/**
|
||||
* @var \SimpleXMLElement
|
||||
*/
|
||||
private $xml;
|
||||
|
||||
/**
|
||||
* @var array<string,array>
|
||||
*/
|
||||
private $indices;
|
||||
|
||||
/**
|
||||
* @param $caseId
|
||||
*/
|
||||
public function __construct($caseId) {
|
||||
$this->caseId = $caseId;
|
||||
$this->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if case includes an activity of given type/status
|
||||
*
|
||||
* @param string $type
|
||||
* Eg "Phone Call", "Interview Prospect", "Background Check".
|
||||
* @param string $status
|
||||
* Eg "Scheduled", "Completed".
|
||||
* @return bool
|
||||
*/
|
||||
public function hasActivity($type, $status = NULL) {
|
||||
$idx = $this->getActivityIndex(array('activity_type_id', 'status_id'));
|
||||
$activityTypeGroup = civicrm_api3('option_group', 'get', array('name' => 'activity_type'));
|
||||
$activityType = array(
|
||||
'name' => $type,
|
||||
'option_group_id' => $activityTypeGroup['id'],
|
||||
);
|
||||
$activityTypeID = civicrm_api3('option_value', 'get', $activityType);
|
||||
$activityTypeID = $activityTypeID['values'][$activityTypeID['id']]['value'];
|
||||
if ($status) {
|
||||
$activityStatusGroup = civicrm_api3('option_group', 'get', array('name' => 'activity_status'));
|
||||
$activityStatus = array(
|
||||
'name' => $status,
|
||||
'option_group_id' => $activityStatusGroup['id'],
|
||||
);
|
||||
$activityStatusID = civicrm_api3('option_value', 'get', $activityStatus);
|
||||
$activityStatusID = $activityStatusID['values'][$activityStatusID['id']]['value'];
|
||||
}
|
||||
if ($status === NULL) {
|
||||
return !empty($idx[$activityTypeID]);
|
||||
}
|
||||
else {
|
||||
return !empty($idx[$activityTypeID][$activityStatusID]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all activities in the case.
|
||||
*
|
||||
* @return array
|
||||
* list of activity records (api/v3 format)
|
||||
*/
|
||||
public function getActivities() {
|
||||
if ($this->activities === NULL) {
|
||||
// TODO find batch-oriented API for getting all activities in a case
|
||||
$case = $this->getCase();
|
||||
$activities = array();
|
||||
if (isset($case['activities'])) {
|
||||
foreach ($case['activities'] as $actId) {
|
||||
$result = civicrm_api3('Activity', 'get', array(
|
||||
'id' => $actId,
|
||||
'is_current_revision' => 1,
|
||||
));
|
||||
$activities = array_merge($activities, $result['values']);
|
||||
}
|
||||
}
|
||||
$this->activities = $activities;
|
||||
}
|
||||
return $this->activities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single activity record by type.
|
||||
*
|
||||
* @param string $type
|
||||
* @throws \Civi\CCase\Exception\MultipleActivityException
|
||||
* @return array|NULL, activity record (api/v3)
|
||||
*/
|
||||
public function getSingleActivity($type) {
|
||||
$idx = $this->getActivityIndex(array('activity_type_id', 'id'));
|
||||
$actTypes = array_flip(\CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'name'));
|
||||
$typeId = $actTypes[$type];
|
||||
$count = isset($idx[$typeId]) ? count($idx[$typeId]) : 0;
|
||||
|
||||
if ($count === 0) {
|
||||
return NULL;
|
||||
}
|
||||
elseif ($count === 1) {
|
||||
foreach ($idx[$typeId] as $item) {
|
||||
return $item;
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new \Civi\CCase\Exception\MultipleActivityException("Wrong quantity of [$type] records. Expected 1 but found " . $count);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getCaseId() {
|
||||
return $this->caseId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array, Case record (api/v3 format)
|
||||
*/
|
||||
public function getCase() {
|
||||
if ($this->case === NULL) {
|
||||
$this->case = civicrm_api3('case', 'getsingle', array('id' => $this->caseId));
|
||||
}
|
||||
return $this->case;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws \CRM_Core_Exception
|
||||
*/
|
||||
public function getCaseType() {
|
||||
if ($this->caseType === NULL) {
|
||||
$case = $this->getCase();
|
||||
$caseTypes = \CRM_Case_XMLRepository::singleton()->getAllCaseTypes();
|
||||
if (!isset($caseTypes[$case['case_type_id']])) {
|
||||
throw new \CRM_Core_Exception("Case does not have a recognized case-type!");
|
||||
}
|
||||
$this->caseType = $caseTypes[$case['case_type_id']];
|
||||
}
|
||||
return $this->caseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all activities in the case (indexed by some property/properties)
|
||||
*
|
||||
* @param array $keys
|
||||
* List of properties by which to index activities.
|
||||
* @return array
|
||||
* list of activity records (api/v3 format), indexed by $keys
|
||||
*/
|
||||
public function getActivityIndex($keys) {
|
||||
$key = implode(";", $keys);
|
||||
if (!isset($this->indices[$key])) {
|
||||
$this->indices[$key] = \CRM_Utils_Array::index($keys, $this->getActivities());
|
||||
}
|
||||
return $this->indices[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \SimpleXMLElement|NULL
|
||||
*/
|
||||
public function getXml() {
|
||||
if ($this->xml === NULL) {
|
||||
$this->xml = \CRM_Case_XMLRepository::singleton()->retrieve($this->getCaseType());
|
||||
}
|
||||
return $this->xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush any cached information.
|
||||
*/
|
||||
public function flush() {
|
||||
$this->case = NULL;
|
||||
$this->caseType = NULL;
|
||||
$this->activities = NULL;
|
||||
$this->indices = array();
|
||||
}
|
||||
|
||||
}
|
42
sites/all/modules/civicrm/Civi/CCase/CaseChangeListener.php
Normal file
42
sites/all/modules/civicrm/Civi/CCase/CaseChangeListener.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM 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 Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
namespace Civi\CCase;
|
||||
|
||||
/**
|
||||
* Interface CaseChangeListener
|
||||
*
|
||||
* @package Civi\CCase
|
||||
*/
|
||||
interface CaseChangeListener {
|
||||
/**
|
||||
* @param \Civi\CCase\Event\CaseChangeEvent $event
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function onCaseChange(\Civi\CCase\Event\CaseChangeEvent $event);
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM 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 Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
namespace Civi\CCase\Event;
|
||||
use Civi\Core\Event\GenericHookEvent;
|
||||
|
||||
/**
|
||||
* Class CaseChangeEvent
|
||||
* @package Civi\API\Event
|
||||
*/
|
||||
class CaseChangeEvent extends GenericHookEvent {
|
||||
/**
|
||||
* @var \Civi\CCase\Analyzer
|
||||
*/
|
||||
public $analyzer;
|
||||
|
||||
/**
|
||||
* @param $analyzer
|
||||
*/
|
||||
public function __construct($analyzer) {
|
||||
$this->analyzer = $analyzer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getHookValues() {
|
||||
return array($this->analyzer);
|
||||
}
|
||||
|
||||
}
|
114
sites/all/modules/civicrm/Civi/CCase/Events.php
Normal file
114
sites/all/modules/civicrm/Civi/CCase/Events.php
Normal file
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM 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 Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
namespace Civi\CCase;
|
||||
|
||||
/**
|
||||
* Class Events
|
||||
*
|
||||
* @package Civi\CCase
|
||||
*/
|
||||
class Events {
|
||||
/**
|
||||
* @var array (int $caseId => bool $active) list of cases for which we are actively firing case-change event
|
||||
*
|
||||
* We do not want to fire case-change events recursively.
|
||||
*/
|
||||
static $isActive = array();
|
||||
|
||||
/**
|
||||
* Following a change to an activity or case, fire the case-change event.
|
||||
*
|
||||
* @param \Civi\Core\Event\PostEvent $event
|
||||
* @throws \CRM_Core_Exception
|
||||
*/
|
||||
public static function fireCaseChange(\Civi\Core\Event\PostEvent $event) {
|
||||
$caseId = NULL;
|
||||
switch ($event->entity) {
|
||||
case 'Activity':
|
||||
if (!empty($event->object->case_id)) {
|
||||
$caseId = $event->object->case_id;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Case':
|
||||
// by the time we get the post-delete event, the record is gone, so
|
||||
// there's nothing to analyze
|
||||
if ($event->action != 'delete') {
|
||||
$caseId = $event->id;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \CRM_Core_Exception("CRM_Case_Listener does not support entity {$event->entity}");
|
||||
}
|
||||
|
||||
if ($caseId) {
|
||||
if (!isset(self::$isActive[$caseId])) {
|
||||
$tx = new \CRM_Core_Transaction();
|
||||
\CRM_Core_Transaction::addCallback(
|
||||
\CRM_Core_Transaction::PHASE_POST_COMMIT,
|
||||
array(__CLASS__, 'fireCaseChangeForRealz'),
|
||||
array($caseId),
|
||||
"Civi_CCase_Events::fire::{$caseId}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire case change hook
|
||||
*
|
||||
* @param int|array $caseIds
|
||||
*/
|
||||
public static function fireCaseChangeForRealz($caseIds) {
|
||||
foreach ((array) $caseIds as $caseId) {
|
||||
if (!isset(self::$isActive[$caseId])) {
|
||||
$tx = new \CRM_Core_Transaction();
|
||||
self::$isActive[$caseId] = 1;
|
||||
$analyzer = new \Civi\CCase\Analyzer($caseId);
|
||||
\CRM_Utils_Hook::caseChange($analyzer);
|
||||
unset(self::$isActive[$caseId]);
|
||||
unset($tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find any extra listeners declared in XML and pass the event along to them.
|
||||
*
|
||||
* @param \Civi\CCase\Event\CaseChangeEvent $event
|
||||
*/
|
||||
public static function delegateToXmlListeners(\Civi\CCase\Event\CaseChangeEvent $event) {
|
||||
$p = new \CRM_Case_XMLProcessor_Process();
|
||||
$listeners = $p->getListeners($event->analyzer->getCaseType());
|
||||
foreach ($listeners as $listener) {
|
||||
/** @var $listener \Civi\CCase\CaseChangeListener */
|
||||
$listener->onCaseChange($event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
namespace Civi\CCase\Exception;
|
||||
|
||||
/**
|
||||
* Class MultipleActivityException
|
||||
*
|
||||
* @package Civi\CCase\Exception
|
||||
*/
|
||||
class MultipleActivityException extends \CRM_Core_Exception {
|
||||
|
||||
}
|
123
sites/all/modules/civicrm/Civi/CCase/SequenceListener.php
Normal file
123
sites/all/modules/civicrm/Civi/CCase/SequenceListener.php
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
namespace Civi\CCase;
|
||||
|
||||
/**
|
||||
* The sequence-listener looks for CiviCase XML tags with "<sequence>". If
|
||||
* a change is made to any record in case-type which uses "<sequence>", then
|
||||
* it attempts to add the next step in the sequence.
|
||||
*/
|
||||
class SequenceListener implements CaseChangeListener {
|
||||
|
||||
/**
|
||||
* @var SequenceListener
|
||||
*/
|
||||
private static $singleton;
|
||||
|
||||
/**
|
||||
* @param bool $reset
|
||||
* Whether to forcibly rebuild the entire container.
|
||||
* @return SequenceListener
|
||||
*/
|
||||
public static function singleton($reset = FALSE) {
|
||||
if ($reset || self::$singleton === NULL) {
|
||||
self::$singleton = new SequenceListener();
|
||||
}
|
||||
return self::$singleton;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Civi\CCase\Event\CaseChangeEvent $event
|
||||
*/
|
||||
public static function onCaseChange_static(\Civi\CCase\Event\CaseChangeEvent $event) {
|
||||
self::singleton()->onCaseChange($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Civi\CCase\Event\CaseChangeEvent $event
|
||||
*
|
||||
* @throws \CiviCRM_API3_Exception
|
||||
* @return void
|
||||
*/
|
||||
public function onCaseChange(\Civi\CCase\Event\CaseChangeEvent $event) {
|
||||
/** @var \Civi\CCase\Analyzer $analyzer */
|
||||
$analyzer = $event->analyzer;
|
||||
|
||||
$activitySetXML = $this->getSequenceXml($analyzer->getXml());
|
||||
if (!$activitySetXML) {
|
||||
return;
|
||||
}
|
||||
|
||||
$actTypes = array_flip(\CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'name'));
|
||||
$actStatuses = array_flip(\CRM_Core_PseudoConstant::activityStatus('name'));
|
||||
|
||||
$actIndex = $analyzer->getActivityIndex(array('activity_type_id', 'status_id'));
|
||||
|
||||
foreach ($activitySetXML->ActivityTypes->ActivityType as $actTypeXML) {
|
||||
$actTypeId = $actTypes[(string) $actTypeXML->name];
|
||||
if (empty($actIndex[$actTypeId])) {
|
||||
// Haven't tried this step yet!
|
||||
$this->createActivity($analyzer, $actTypeXML);
|
||||
return;
|
||||
}
|
||||
elseif (empty($actIndex[$actTypeId][$actStatuses['Completed']])) {
|
||||
// Haven't gotten past this step yet!
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//CRM-17452 - Close the case only if all the activities are complete
|
||||
$activities = $analyzer->getActivities();
|
||||
foreach ($activities as $activity) {
|
||||
if ($activity['status_id'] != $actStatuses['Completed']) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// OK, the all activities have completed
|
||||
civicrm_api3('Case', 'create', array(
|
||||
'id' => $analyzer->getCaseId(),
|
||||
'status_id' => 'Closed',
|
||||
));
|
||||
$analyzer->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the ActivitySet which defines the pipeline.
|
||||
*
|
||||
* @param \SimpleXMLElement $xml
|
||||
* @return \SimpleXMLElement|NULL
|
||||
*/
|
||||
public function getSequenceXml($xml) {
|
||||
if ($xml->ActivitySets && $xml->ActivitySets->ActivitySet) {
|
||||
foreach ($xml->ActivitySets->ActivitySet as $activitySetXML) {
|
||||
$seq = (string) $activitySetXML->sequence;
|
||||
if ($seq && strtolower($seq) == 'true') {
|
||||
if ($activitySetXML->ActivityTypes && $activitySetXML->ActivityTypes->ActivityType) {
|
||||
return $activitySetXML;
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Analyzer $analyzer
|
||||
* The case being analyzed -- to which we want to add an activity.
|
||||
* @param \SimpleXMLElement $actXML the <ActivityType> tag which describes the new activity
|
||||
*/
|
||||
public function createActivity(Analyzer $analyzer, \SimpleXMLElement $actXML) {
|
||||
$params = array(
|
||||
'activity_type_id' => (string) $actXML->name,
|
||||
'status_id' => 'Scheduled',
|
||||
'activity_date_time' => \CRM_Utils_Time::getTime('YmdHis'),
|
||||
'case_id' => $analyzer->getCaseId(),
|
||||
);
|
||||
$r = civicrm_api3('Activity', 'create', $params);
|
||||
$analyzer->flush();
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue