Skip to content

Commit

Permalink
FOSFAB-320: Add functionality to link cases while creating a case
Browse files Browse the repository at this point in the history
  • Loading branch information
Muhammad Shahrukh committed Jul 30, 2024
1 parent fd53403 commit 30fbf0c
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 6 deletions.
139 changes: 139 additions & 0 deletions CRM/Civicase/Hook/Post/LinkCase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?php

use Civi\Api4\CiviCase;
use Civi\Api4\Contact;

/**
* Handles link case logic when case is created.
*/
class CRM_Civicase_Hook_Post_LinkCase {

/**
* Link Cases.
*
* @param string $op
* The operation being performed.
* @param string $objectName
* Object name.
* @param int $objectId
* Object ID.
* @param object $objectRef
* Object reference.
*/
public function run(string $op, string $objectName, ?int $objectId, &$objectRef) {
if (!$this->shouldRun($op, $objectName)) {
return;
}

$linkToCaseId = (int) CRM_Utils_Request::retrieve('linkToCaseId', 'Positive');
$linkedToCaseDetails = $this->getLinkedToCaseDetails($linkToCaseId);
$caseDetails = $this->getCaseDetails($objectId);

$params = [
'case_id' => $linkToCaseId,
'link_to_case_id' => $objectId,
'activity_type_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Link Cases'),
'medium_id' => CRM_Core_OptionGroup::values('encounter_medium', FALSE, FALSE, FALSE, 'AND is_default = 1'),
'activity_date_time' => date('YmdHis'),
'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_status_id', 'Completed'),
'subject' => $this->getActivitySubject($caseDetails, $linkedToCaseDetails),
'source_contact_id' => \CRM_Core_Session::getLoggedInContactID(),
'target_contact_id' => $linkedToCaseContacts[0]['contact_id'] ?? NULL,
];

$activity = CRM_Activity_BAO_Activity::create($params);

$caseParams = [
'case_id' => $objectId,
'activity_id' => $activity->id,
];
CRM_Case_BAO_Case::processCaseActivity($caseParams);
}

/**
* Determines if the hook should run or not.
*
* @param string $op
* The operation being performed.
* @param string $objectName
* Object name.
*
* @return bool
* returns a boolean to determine if hook will run or not.
*/
private function shouldRun(string $op, string $objectName): bool {
return $objectName == 'Case' && $op === 'create'
&& (int) CRM_Utils_Request::retrieve('linkToCaseId', 'Positive') > 0;
}

/**
* Get case details required to create the activity subject.
*
* @param int $id
* The case id.
*
* @return array
* case details.
*/
private function getLinkedToCaseDetails(int $id): array {
$case = CiviCase::get(FALSE)
->addSelect('contact.display_name', 'case_type_id.title')
->addJoin('CaseContact AS case_contact', 'INNER', ['id', '=', 'case_contact.case_id'])
->addJoin('Contact AS contact', 'INNER', ['contact.id', '=', 'case_contact.contact_id'])
->addWhere('id', '=', $id)
->execute()
->first();

return [
'id' => $id,
'caseType' => $case['case_type_id.title'] ?? '',
'contact' => $case['contact.display_name'] ?? '',
];
}

/**
* Get case details required to create the activity subject.
*
* @param int $id
* The case id.
*
* @return array
* case details.
*/
private function getCaseDetails(int $id): array {
$caseClient = Contact::get(FALSE)
->addSelect('display_name')
->addWhere('id', '=', $_POST['client_id'] ?? 0)
->execute()
->first();

return [
'id' => $id,
'caseType' => CRM_Case_BAO_Case::getCaseType($id),
'contact' => $caseClient['display_name'] ?? '',
];
}

/**
* Create activity subject.
*
* @param array $caseDetails
* The case details.
* @param array $linkedToCaseDetails
* The linked to case details.
*
* @return string
* Activity subject.
*/
private function getActivitySubject(array $caseDetails, array $linkedToCaseDetails): string {
return ts('Create link between %1 - %2 (CaseID: %3) and %4 - %5 (CaseID: %6)', [
1 => $caseDetails['contact'],
2 => $caseDetails['caseType'],
3 => $caseDetails['id'],
4 => $linkedToCaseDetails['contact'],
5 => $linkedToCaseDetails['caseType'],
6 => $linkedToCaseDetails['id'],
]);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
(function (angular, $, _) {
var module = angular.module('civicase');

module.service('NewLinkCasesCaseAction', NewLinkCasesCaseAction);

/**
* Create and Link Case Action service
*
* @param {object} $q $q service
* @param {object} ActivityType ActivityType
*/
function NewLinkCasesCaseAction ($q, ActivityType) {
/**
* Click event handler for the Action
*
* @param {object} cases cases
*
* @returns {Promise} promise which resolves to the path for the popup
*/
this.doAction = function (cases) {
var currentCase = cases[0];
var activityTypes = ActivityType.getAll(true);

var link = {
path: 'civicrm/case/add',
query: {
action: 'add',
reset: 1,
atype: _.findKey(activityTypes, { name: 'Open Case' }),
linkToCaseId: currentCase.id,
context: 'standalone'
}
};

return $q.resolve(link);
};
}
})(angular, CRM.$, CRM._);
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@
<i class="fa fa-link"></i>
{{ ts('Link Cases') }}
</button>
<button
class="btn btn-large btn-primary"
ng-click="newLinkCase()"
>
<i class="fa fa-link"></i>
{{ ts('Create new linked Case') }}
</button>
</div>
<civicase-case-summary-other-cases
ng-if="item.relatedCases.length"
Expand All @@ -20,10 +27,17 @@
<div class="civicase__activity-card--big--empty-description">
{{ ts('Click the button below to create a new link for this case') }}
</div>
<a
class="civicase__activity-card--big--empty-button btn"
ng-click="linkCase()">
{{ ts('Link Cases') }}
</a>
<div>
<a
class="civicase__activity-card--big--empty-button btn"
ng-click="linkCase()">
{{ ts('Link Cases') }}
</a>
<a
class="civicase__activity-card--big--empty-button btn"
ng-click="newLinkCase()">
{{ ts('Create new linked Case') }}
</a>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
*
* @param {object} $scope the scope object.
* @param {object} LinkCasesCaseAction the link case action service.
* @param {object} NewLinkCasesCaseAction the new link case action service.
* @param {Function} civicaseCrmUrl crm url service.
* @param {Function} civicaseCrmLoadForm service to load civicrm forms
*/
function civicaseCaseDetailsLinkedCasesTabController ($scope,
LinkCasesCaseAction, civicaseCrmUrl, civicaseCrmLoadForm) {
LinkCasesCaseAction, NewLinkCasesCaseAction, civicaseCrmUrl, civicaseCrmLoadForm) {
$scope.linkCase = linkCase;
$scope.newLinkCase = newLinkCase;

/**
* Opens a modal that allows the user to link the case stored in the scope with
Expand All @@ -39,5 +41,20 @@
});
});
}

/**
* Opens a modal that allows the user to open a new case and link it at the same time.
*
* The case details are refreshed after linking the cases.
*/
function newLinkCase () {
NewLinkCasesCaseAction.doAction([$scope.item])
.then(function (openCaseForm) {
civicaseCrmLoadForm(civicaseCrmUrl(openCaseForm.path, openCaseForm.query))
.on('crmFormSuccess crmPopupFormSuccess', function () {
$scope.refresh();
});
});
}
}
})(angular);
1 change: 1 addition & 0 deletions civicase.php
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ function civicase_civicrm_post($op, $objectName, $objectId, &$objectRef) {
new CRM_Civicase_Hook_Post_PopulateCaseCategoryForCaseType(),
new CRM_Civicase_Hook_Post_CaseCategoryCustomGroupSaver(),
new CRM_Civicase_Hook_Post_UpdateCaseTypeListForCaseCategoryCustomGroup(),
new CRM_Civicase_Hook_Post_LinkCase(),
];

foreach ($hooks as $hook) {
Expand Down

0 comments on commit 30fbf0c

Please sign in to comment.