fix version in header
[civicrm-core.git] / CRM / Case / XMLProcessor / Process.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
39de6fd5 4 | CiviCRM version 4.6 |
6a488035 5 +--------------------------------------------------------------------+
06b69b18 6 | Copyright CiviCRM LLC (c) 2004-2014 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26*/
27
28/**
29 *
30 * @package CRM
06b69b18 31 * @copyright CiviCRM LLC (c) 2004-2014
6a488035
TO
32 * $Id$
33 *
34 */
35class CRM_Case_XMLProcessor_Process extends CRM_Case_XMLProcessor {
4c6ce474
EM
36 /**
37 * @param $caseType
c490a46a 38 * @param array $params
4c6ce474
EM
39 *
40 * @throws Exception
41 */
6a488035
TO
42 function run($caseType, &$params) {
43 $xml = $this->retrieve($caseType);
44
45 if ($xml === FALSE) {
46 $docLink = CRM_Utils_System::docURL2("user/case-management/setup");
47 CRM_Core_Error::fatal(ts("Configuration file could not be retrieved for case type = '%1' %2.",
48 array(1 => $caseType, 2 => $docLink)
49 ));
50 return FALSE;
51 }
52
53 $xmlProcessorProcess = new CRM_Case_XMLProcessor_Process();
54 $this->_isMultiClient = $xmlProcessorProcess->getAllowMultipleCaseClients();
55
56 $this->process($xml, $params);
57 }
58
4c6ce474
EM
59 /**
60 * @param $caseType
61 * @param $fieldSet
62 * @param bool $isLabel
63 * @param bool $maskAction
64 *
65 * @return array|bool|mixed
66 * @throws Exception
67 */
6a488035
TO
68 function get($caseType, $fieldSet, $isLabel = FALSE, $maskAction = FALSE) {
69 $xml = $this->retrieve($caseType);
70 if ($xml === FALSE) {
71 $docLink = CRM_Utils_System::docURL2("user/case-management/setup");
72 CRM_Core_Error::fatal(ts("Unable to load configuration file for the referenced case type: '%1' %2.",
73 array(1 => $caseType, 2 => $docLink)
74 ));
75 return FALSE;
76 }
77
78 switch ($fieldSet) {
79 case 'CaseRoles':
80 return $this->caseRoles($xml->CaseRoles);
81
82 case 'ActivitySets':
83 return $this->activitySets($xml->ActivitySets);
84
85 case 'ActivityTypes':
86 return $this->activityTypes($xml->ActivityTypes, FALSE, $isLabel, $maskAction);
87 }
88 }
89
4c6ce474
EM
90 /**
91 * @param $xml
c490a46a 92 * @param array $params
4c6ce474
EM
93 *
94 * @throws Exception
95 */
6a488035
TO
96 function process($xml, &$params) {
97 $standardTimeline = CRM_Utils_Array::value('standardTimeline', $params);
98 $activitySetName = CRM_Utils_Array::value('activitySetName', $params);
99 $activityTypeName = CRM_Utils_Array::value('activityTypeName', $params);
100
101 if ('Open Case' == CRM_Utils_Array::value('activityTypeName', $params)) {
102 // create relationships for the ones that are required
103 foreach ($xml->CaseRoles as $caseRoleXML) {
104 foreach ($caseRoleXML->RelationshipType as $relationshipTypeXML) {
105 if ((int ) $relationshipTypeXML->creator == 1) {
106 if (!$this->createRelationships((string ) $relationshipTypeXML->name,
107 $params
108 )) {
109 CRM_Core_Error::fatal();
110 return FALSE;
111 }
112 }
113 }
114 }
115 }
116
117 if ('Change Case Start Date' == CRM_Utils_Array::value('activityTypeName', $params)) {
118 // delete all existing activities which are non-empty
119 $this->deleteEmptyActivity($params);
120 }
121
122 foreach ($xml->ActivitySets as $activitySetsXML) {
123 foreach ($activitySetsXML->ActivitySet as $activitySetXML) {
124 if ($standardTimeline) {
125 if ((boolean ) $activitySetXML->timeline) {
126 return $this->processStandardTimeline($activitySetXML,
127 $params
128 );
129 }
130 }
131 elseif ($activitySetName) {
132 $name = (string ) $activitySetXML->name;
133 if ($name == $activitySetName) {
134 return $this->processActivitySet($activitySetXML,
135 $params
136 );
137 }
138 }
139 }
140 }
141 }
142
4c6ce474
EM
143 /**
144 * @param $activitySetXML
c490a46a 145 * @param array $params
4c6ce474 146 */
6a488035 147 function processStandardTimeline($activitySetXML, &$params) {
448e7600
PJ
148 if ('Change Case Type' == CRM_Utils_Array::value('activityTypeName', $params)
149 && CRM_Utils_Array::value('resetTimeline', $params, TRUE)) {
6a488035
TO
150 // delete all existing activities which are non-empty
151 $this->deleteEmptyActivity($params);
152 }
153
154 foreach ($activitySetXML->ActivityTypes as $activityTypesXML) {
155 foreach ($activityTypesXML as $activityTypeXML) {
156 $this->createActivity($activityTypeXML, $params);
157 }
158 }
159 }
160
4c6ce474
EM
161 /**
162 * @param $activitySetXML
c490a46a 163 * @param array $params
4c6ce474 164 */
6a488035
TO
165 function processActivitySet($activitySetXML, &$params) {
166 foreach ($activitySetXML->ActivityTypes as $activityTypesXML) {
167 foreach ($activityTypesXML as $activityTypeXML) {
168 $this->createActivity($activityTypeXML, $params);
169 }
170 }
171 }
172
4c6ce474
EM
173 /**
174 * @param $caseRolesXML
175 * @param bool $isCaseManager
176 *
177 * @return array|mixed
178 */
6a488035
TO
179 function &caseRoles($caseRolesXML, $isCaseManager = FALSE) {
180 $relationshipTypes = &$this->allRelationshipTypes();
181
182 $result = array();
183 foreach ($caseRolesXML as $caseRoleXML) {
184 foreach ($caseRoleXML->RelationshipType as $relationshipTypeXML) {
185 $relationshipTypeName = (string ) $relationshipTypeXML->name;
186 $relationshipTypeID = array_search($relationshipTypeName,
187 $relationshipTypes
188 );
189 if ($relationshipTypeID === FALSE) {
190 continue;
191 }
192
193 if (!$isCaseManager) {
194 $result[$relationshipTypeID] = $relationshipTypeName;
195 }
196 elseif ($relationshipTypeXML->manager) {
197 return $relationshipTypeID;
198 }
199 }
200 }
201 return $result;
202 }
203
4c6ce474 204 /**
100fef9d 205 * @param string $relationshipTypeName
c490a46a 206 * @param array $params
4c6ce474
EM
207 *
208 * @return bool
209 * @throws Exception
210 */
6a488035
TO
211 function createRelationships($relationshipTypeName, &$params) {
212 $relationshipTypes = &$this->allRelationshipTypes();
213 // get the relationship id
214 $relationshipTypeID = array_search($relationshipTypeName, $relationshipTypes);
215
216 if ($relationshipTypeID === FALSE) {
217 $docLink = CRM_Utils_System::docURL2("user/case-management/setup");
218 CRM_Core_Error::fatal(ts('Relationship type %1, found in case configuration file, is not present in the database %2',
219 array(1 => $relationshipTypeName, 2 => $docLink)
220 ));
221 return FALSE;
222 }
223
224 $client = $params['clientID'];
225 if (!is_array($client)) {
226 $client = array($client);
227 }
228
229 foreach ($client as $key => $clientId) {
230 $relationshipParams = array(
231 'relationship_type_id' => $relationshipTypeID,
232 'contact_id_a' => $clientId,
233 'contact_id_b' => $params['creatorID'],
234 'is_active' => 1,
235 'case_id' => $params['caseID'],
236 'start_date' => date("Ymd"),
237 );
238
239 if (!$this->createRelationship($relationshipParams)) {
240 CRM_Core_Error::fatal();
241 return FALSE;
242 }
243 }
244 return TRUE;
245 }
246
4c6ce474 247 /**
c490a46a 248 * @param array $params
4c6ce474
EM
249 *
250 * @return bool
251 */
6a488035
TO
252 function createRelationship(&$params) {
253 $dao = new CRM_Contact_DAO_Relationship();
254 $dao->copyValues($params);
255 // only create a relationship if it does not exist
256 if (!$dao->find(TRUE)) {
257 $dao->save();
258 }
259 return TRUE;
260 }
261
4c6ce474
EM
262 /**
263 * @param $activityTypesXML
264 * @param bool $maxInst
265 * @param bool $isLabel
266 * @param bool $maskAction
267 *
268 * @return array
269 */
6a488035
TO
270 function activityTypes($activityTypesXML, $maxInst = FALSE, $isLabel = FALSE, $maskAction = FALSE) {
271 $activityTypes = &$this->allActivityTypes(TRUE, TRUE);
272 $result = array();
273 foreach ($activityTypesXML as $activityTypeXML) {
274 foreach ($activityTypeXML as $recordXML) {
275 $activityTypeName = (string ) $recordXML->name;
276 $maxInstances = (string ) $recordXML->max_instances;
277 $activityTypeInfo = CRM_Utils_Array::value($activityTypeName, $activityTypes);
278
279 if ($activityTypeInfo['id']) {
280 if ($maskAction) {
281 if ($maskAction == 'edit' && '0' === (string ) $recordXML->editable) {
282 $result[$maskAction][] = $activityTypeInfo['id'];
283 }
284 }
285 else {
286 if (!$maxInst) {
287 //if we want,labels of activities should be returned.
288 if ($isLabel) {
289 $result[$activityTypeInfo['id']] = $activityTypeInfo['label'];
290 }
291 else {
292 $result[$activityTypeInfo['id']] = $activityTypeName;
293 }
294 }
295 else {
296 if ($maxInstances) {
297 $result[$activityTypeName] = $maxInstances;
298 }
299 }
300 }
301 }
302 }
303 }
304
305 // call option value hook
306 CRM_Utils_Hook::optionValues($result, 'case_activity_type');
307
308 return $result;
309 }
310
e19323c9
TO
311 /**
312 * @param SimpleXMLElement $caseTypeXML
313 * @return array<string> symbolic activity-type names
314 */
315 function getDeclaredActivityTypes($caseTypeXML) {
316 $result = array();
83151a3f
DJ
317
318 if (!empty($caseTypeXML->ActivityTypes) && $caseTypeXML->ActivityTypes->ActivityType) {
319 foreach ($caseTypeXML->ActivityTypes->ActivityType as $activityTypeXML) {
320 $result[] = (string) $activityTypeXML->name;
e19323c9 321 }
83151a3f 322 }
e19323c9 323
83151a3f
DJ
324 if (!empty($caseTypeXML->ActivitySets) && $caseTypeXML->ActivitySets->ActivitySet) {
325 foreach ($caseTypeXML->ActivitySets->ActivitySet as $activitySetXML) {
326 if ($activitySetXML->ActivityTypes && $activitySetXML->ActivityTypes->ActivityType) {
327 foreach ($activitySetXML->ActivityTypes->ActivityType as $activityTypeXML) {
328 $result[] = (string) $activityTypeXML->name;
e19323c9
TO
329 }
330 }
331 }
332 }
83151a3f 333
e19323c9
TO
334 $result = array_unique($result);
335 sort($result);
336 return $result;
337 }
338
339 /**
340 * @param SimpleXMLElement $caseTypeXML
341 * @return array<string> symbolic relationship-type names
342 */
343 function getDeclaredRelationshipTypes($caseTypeXML) {
344 $result = array();
83151a3f
DJ
345
346 if (!empty($caseTypeXML->CaseRoles) && $caseTypeXML->CaseRoles->RelationshipType) {
347 foreach ($caseTypeXML->CaseRoles->RelationshipType as $relTypeXML) {
348 $result[] = (string) $relTypeXML->name;
e19323c9
TO
349 }
350 }
83151a3f 351
e19323c9
TO
352 $result = array_unique($result);
353 sort($result);
354 return $result;
355 }
356
4c6ce474 357 /**
c490a46a 358 * @param array $params
4c6ce474 359 */
6a488035 360 function deleteEmptyActivity(&$params) {
e7e657f0 361 $activityContacts = CRM_Core_OptionGroup::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name');
9e74e3ce 362 $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
8ef12e64 363
6a488035
TO
364 $query = "
365DELETE a
366FROM civicrm_activity a
91da6cd5
DL
367INNER JOIN civicrm_activity_contact t ON t.activity_id = a.id
368WHERE t.contact_id = %1
9e74e3ce 369AND t.record_type_id = $targetID
6a488035
TO
370AND a.is_auto = 1
371AND a.is_current_revision = 1
372";
373 $sqlParams = array(1 => array($params['clientID'], 'Integer'));
374 CRM_Core_DAO::executeQuery($query, $sqlParams);
375 }
376
4c6ce474 377 /**
c490a46a 378 * @param array $params
4c6ce474
EM
379 *
380 * @return bool
381 */
6a488035
TO
382 function isActivityPresent(&$params) {
383 $query = "
384SELECT count(a.id)
385FROM civicrm_activity a
386INNER JOIN civicrm_case_activity ca on ca.activity_id = a.id
387WHERE a.activity_type_id = %1
388AND ca.case_id = %2
389AND a.is_deleted = 0
390";
391
392 $sqlParams = array(1 => array($params['activityTypeID'], 'Integer'),
393 2 => array($params['caseID'], 'Integer'),
394 );
395 $count = CRM_Core_DAO::singleValueQuery($query, $sqlParams);
396
397 // check for max instance
6f55186b 398 $caseType = CRM_Case_BAO_Case::getCaseType($params['caseID'], 'name');
6a488035
TO
399 $maxInstance = self::getMaxInstance($caseType, $params['activityTypeName']);
400
401 return $maxInstance ? ($count < $maxInstance ? FALSE : TRUE) : FALSE;
402 }
403
4c6ce474
EM
404 /**
405 * @param $activityTypeXML
c490a46a 406 * @param array $params
4c6ce474
EM
407 *
408 * @return bool
409 * @throws CRM_Core_Exception
410 * @throws Exception
411 */
6a488035
TO
412 function createActivity($activityTypeXML, &$params) {
413 $activityTypeName = (string) $activityTypeXML->name;
414 $activityTypes = &$this->allActivityTypes(TRUE, TRUE);
415 $activityTypeInfo = CRM_Utils_Array::value($activityTypeName, $activityTypes);
416
417 if (!$activityTypeInfo) {
418 $docLink = CRM_Utils_System::docURL2("user/case-management/setup");
419 CRM_Core_Error::fatal(ts('Activity type %1, found in case configuration file, is not present in the database %2',
420 array(1 => $activityTypeName, 2 => $docLink)
421 ));
422 return FALSE;
423 }
424
425 $activityTypeID = $activityTypeInfo['id'];
426
427 if (isset($activityTypeXML->status)) {
428 $statusName = (string) $activityTypeXML->status;
429 }
430 else {
431 $statusName = 'Scheduled';
432 }
433
434 if ($this->_isMultiClient) {
435 $client = $params['clientID'];
436 }
437 else {
438 $client = array(1 => $params['clientID']);
439 }
440
441 //set order
442 $orderVal = '';
443 if (isset($activityTypeXML->order)) {
444 $orderVal = (string) $activityTypeXML->order;
445 }
446
447 if ($activityTypeName == 'Open Case') {
448 $activityParams = array(
449 'activity_type_id' => $activityTypeID,
450 'source_contact_id' => $params['creatorID'],
451 'is_auto' => FALSE,
452 'is_current_revision' => 1,
453 'subject' => CRM_Utils_Array::value('subject', $params) ? $params['subject'] : $activityTypeName,
454 'status_id' => CRM_Core_OptionGroup::getValue('activity_status',
455 $statusName,
456 'name'
457 ),
458 'target_contact_id' => $client,
459 'medium_id' => CRM_Utils_Array::value('medium_id', $params),
460 'location' => CRM_Utils_Array::value('location', $params),
461 'details' => CRM_Utils_Array::value('details', $params),
462 'duration' => CRM_Utils_Array::value('duration', $params),
463 'weight' => $orderVal,
464 );
465 }
466 else {
467 $activityParams = array(
468 'activity_type_id' => $activityTypeID,
469 'source_contact_id' => $params['creatorID'],
470 'is_auto' => TRUE,
471 'is_current_revision' => 1,
472 'status_id' => CRM_Core_OptionGroup::getValue('activity_status',
473 $statusName,
474 'name'
475 ),
476 'target_contact_id' => $client,
477 'weight' => $orderVal,
478 );
479 }
480
481 //parsing date to default preference format
482 $params['activity_date_time'] = CRM_Utils_Date::processDate($params['activity_date_time']);
483
484 if ($activityTypeName == 'Open Case') {
485 // we don't set activity_date_time for auto generated
486 // activities, but we want it to be set for open case.
487 $activityParams['activity_date_time'] = $params['activity_date_time'];
488 if (array_key_exists('custom', $params) && is_array($params['custom'])) {
489 $activityParams['custom'] = $params['custom'];
490 }
491
492 // Add parameters for attachments
493
494 $numAttachments = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'max_attachments');
495 for ( $i = 1; $i <= $numAttachments; $i++ ) {
496 $attachName = "attachFile_$i";
497 if ( isset( $params[$attachName] ) && !empty( $params[$attachName] ) ) {
498 $activityParams[$attachName] = $params[$attachName];
499 }
500 }
501 }
502 else {
503 $activityDate = NULL;
504 //get date of reference activity if set.
505 if ($referenceActivityName = (string) $activityTypeXML->reference_activity) {
506
507 //we skip open case as reference activity.CRM-4374.
a7488080 508 if (!empty($params['resetTimeline']) && $referenceActivityName == 'Open Case') {
6a488035
TO
509 $activityDate = $params['activity_date_time'];
510 }
511 else {
512 $referenceActivityInfo = CRM_Utils_Array::value($referenceActivityName, $activityTypes);
513 if ($referenceActivityInfo['id']) {
514 $caseActivityParams = array('activity_type_id' => $referenceActivityInfo['id']);
515
516 //if reference_select is set take according activity.
517 if ($referenceSelect = (string) $activityTypeXML->reference_select) {
518 $caseActivityParams[$referenceSelect] = 1;
519 }
520
521 $referenceActivity = CRM_Case_BAO_Case::getCaseActivityDates($params['caseID'], $caseActivityParams, TRUE);
522
523 if (is_array($referenceActivity)) {
524 foreach ($referenceActivity as $aId => $details) {
525 $activityDate = CRM_Utils_Array::value('activity_date', $details);
526 break;
527 }
528 }
529 }
530 }
531 }
532 if (!$activityDate) {
533 $activityDate = $params['activity_date_time'];
534 }
535 list($activity_date, $activity_time) = CRM_Utils_Date::setDateDefaults($activityDate);
536 $activityDateTime = CRM_Utils_Date::processDate($activity_date, $activity_time);
537 //add reference offset to date.
538 if ((int) $activityTypeXML->reference_offset) {
539 $activityDateTime = CRM_Utils_Date::intervalAdd('day', (int) $activityTypeXML->reference_offset,
540 $activityDateTime
541 );
542 }
543
544 $activityParams['activity_date_time'] = CRM_Utils_Date::format($activityDateTime);
545 }
546
547 // if same activity is already there, skip and dont touch
548 $params['activityTypeID'] = $activityTypeID;
549 $params['activityTypeName'] = $activityTypeName;
550 if ($this->isActivityPresent($params)) {
551 return TRUE;
552 }
553 $activityParams['case_id'] = $params['caseID'];
a7488080 554 if (!empty($activityParams['is_auto'])) {
6a488035
TO
555 $activityParams['skipRecentView'] = TRUE;
556 }
557
558 $activity = CRM_Activity_BAO_Activity::create($activityParams);
559
560 if (!$activity) {
561 CRM_Core_Error::fatal();
562 return FALSE;
563 }
564
565 // create case activity record
566 $caseParams = array(
567 'activity_id' => $activity->id,
568 'case_id' => $params['caseID'],
569 );
570 CRM_Case_BAO_Case::processCaseActivity($caseParams);
571 return TRUE;
572 }
573
4c6ce474
EM
574 /**
575 * @param $activitySetsXML
576 *
577 * @return array
578 */
916bdc36 579 static function activitySets($activitySetsXML) {
6a488035
TO
580 $result = array();
581 foreach ($activitySetsXML as $activitySetXML) {
582 foreach ($activitySetXML as $recordXML) {
583 $activitySetName = (string ) $recordXML->name;
584 $activitySetLabel = (string ) $recordXML->label;
585 $result[$activitySetName] = $activitySetLabel;
586 }
587 }
588
589 return $result;
590 }
591
4c6ce474
EM
592 /**
593 * @param $caseType
594 * @param null $activityTypeName
595 *
596 * @return array|bool|mixed
597 * @throws Exception
598 */
6a488035
TO
599 function getMaxInstance($caseType, $activityTypeName = NULL) {
600 $xml = $this->retrieve($caseType);
601
602 if ($xml === FALSE) {
603 CRM_Core_Error::fatal();
604 return FALSE;
605 }
606
607 $activityInstances = $this->activityTypes($xml->ActivityTypes, TRUE);
608 return $activityTypeName ? CRM_Utils_Array::value($activityTypeName, $activityInstances) : $activityInstances;
609 }
610
4c6ce474
EM
611 /**
612 * @param $caseType
613 *
614 * @return array|mixed
615 */
6a488035
TO
616 function getCaseManagerRoleId($caseType) {
617 $xml = $this->retrieve($caseType);
618 return $this->caseRoles($xml->CaseRoles, TRUE);
619 }
620
708d8fa2
TO
621 /**
622 * @param string $caseType
623 * @return array<\Civi\CCase\CaseChangeListener>
624 */
625 function getListeners($caseType) {
626 $xml = $this->retrieve($caseType);
627 $listeners = array();
628 if ($xml->Listeners && $xml->Listeners->Listener) {
629 foreach ($xml->Listeners->Listener as $listenerXML) {
630 $class = (string) $listenerXML;
631 $listeners[] = new $class();
632 }
633 }
634 return $listeners;
635 }
636
4c6ce474
EM
637 /**
638 * @return int
639 */
6a488035
TO
640 function getRedactActivityEmail() {
641 $xml = $this->retrieve("Settings");
642 return ( string ) $xml->RedactActivityEmail ? 1 : 0;
643 }
644
645 /**
646 * Retrieves AllowMultipleCaseClients setting
647 *
648 * @return string 1 if allowed, 0 if not
649 */
650 function getAllowMultipleCaseClients() {
651 $xml = $this->retrieve("Settings");
652 if ($xml) {
653 return ( string ) $xml->AllowMultipleCaseClients ? 1 : 0;
654 }
655 return 0;
656 }
657
658 /**
659 * Retrieves NaturalActivityTypeSort setting
660 *
661 * @return string 1 if natural, 0 if alphabetic
662 */
663 function getNaturalActivityTypeSort() {
664 $xml = $this->retrieve("Settings");
665 return ( string ) $xml->NaturalActivityTypeSort ? 1 : 0;
666 }
667}
668