dev/core#641: Implementing Case Activity Assignment Restriction functionality
authorTunbola Ogunwande <tunbolawande@yahoo.com>
Thu, 7 Feb 2019 14:34:16 +0000 (15:34 +0100)
committerTunbola Ogunwande <tunbolawande@yahoo.com>
Mon, 18 Mar 2019 17:40:02 +0000 (18:40 +0100)
CRM/Case/BAO/CaseType.php
CRM/Case/Form/Activity.php
ang/crmCaseType.js
ang/crmCaseType/caseTypeDetails.html

index ec5210d13d5976f2c725fbc33354585d9ace52e4..aa65688f876683d14434e72bfa0a9c5b0f50c981 100644 (file)
@@ -190,7 +190,20 @@ class CRM_Case_BAO_CaseType extends CRM_Case_DAO_CaseType {
       $xmlFile .= "</CaseRoles>\n";
     }
 
+    if (array_key_exists('restrictActivityAsgmtToCmsUser', $definition)) {
+      $xmlFile .= "<RestrictActivityAsgmtToCmsUser>" . $definition['restrictActivityAsgmtToCmsUser'] . "</RestrictActivityAsgmtToCmsUser>\n";
+    }
+
+    if (!empty($definition['activityAsgmtGrps'])) {
+      $xmlFile .= "<ActivityAsgmtGrps>\n";
+      foreach ($definition['activityAsgmtGrps'] as $value) {
+        $xmlFile .= "<Group>$value</Group>\n";
+      }
+      $xmlFile .= "</ActivityAsgmtGrps>\n";
+    }
+
     $xmlFile .= '</CaseType>';
+
     return $xmlFile;
   }
 
@@ -226,6 +239,14 @@ class CRM_Case_BAO_CaseType extends CRM_Case_DAO_CaseType {
       $definition['forkable'] = (int) $xml->forkable;
     }
 
+    if (isset($xml->RestrictActivityAsgmtToCmsUser)) {
+      $definition['restrictActivityAsgmtToCmsUser'] = (int) $xml->RestrictActivityAsgmtToCmsUser;
+    }
+
+    if (isset($xml->ActivityAsgmtGrps)) {
+      $definition['activityAsgmtGrps'] = (array) $xml->ActivityAsgmtGrps->Group;
+    }
+
     // set activity types
     if (isset($xml->ActivityTypes)) {
       $definition['activityTypes'] = array();
index 7a7b3b92b6c76f641b6335542f4bbf2ab20b3991..9e2dda642d8844f27fff2b9b9661790cab638147 100644 (file)
 class CRM_Case_Form_Activity extends CRM_Activity_Form_Activity {
 
   /**
-   * The default variable defined.
+   * Cases this activity belongs to.
    *
-   * @var int
+   * @var []int
    */
   public $_caseId;
 
   /**
    * The default case type variable defined.
    *
-   * @var int
+   * @var []int
    */
   public $_caseType;
 
@@ -57,12 +57,20 @@ class CRM_Case_Form_Activity extends CRM_Activity_Form_Activity {
    */
   public $_relatedContacts;
 
+  /**
+   * The case type definition column info
+   * for the caseId;
+   *
+   * @var array
+   */
+  public $_caseTypeDefinition;
+
   /**
    * Build the form object.
    */
   public function preProcess() {
-    $caseIds = CRM_Utils_Request::retrieve('caseid', 'String', $this);
-    $this->_caseId = explode(',', $caseIds);
+    $caseIds = CRM_Utils_Request::retrieve('caseid', 'CommaSeparatedIntegers', $this);
+    $this->_caseId = $caseIds ? explode(',', $caseIds) : [];
     $this->_context = CRM_Utils_Request::retrieve('context', 'Alphanumeric', $this);
     if (!$this->_context) {
       $this->_context = 'caseActivity';
@@ -76,7 +84,7 @@ class CRM_Case_Form_Activity extends CRM_Activity_Form_Activity {
     $this->assign('scheduleStatusId', $scheduleStatusId);
 
     if (!$this->_caseId && $this->_activityId) {
-      $this->_caseId = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseActivity', $this->_activityId,
+      $this->_caseId = (array) CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseActivity', $this->_activityId,
         'case_id', 'activity_id'
       );
     }
@@ -124,6 +132,8 @@ class CRM_Case_Form_Activity extends CRM_Activity_Form_Activity {
     }
     $this->assign('caseType', $this->_caseType);
 
+    $this->_caseTypeDefinition = $this->getCaseTypeDefinition();
+
     $xmlProcessorProcess = new CRM_Case_XMLProcessor_Process();
     $isMultiClient = $xmlProcessorProcess->getAllowMultipleCaseClients();
     $this->assign('multiClient', $isMultiClient);
@@ -248,10 +258,31 @@ class CRM_Case_Form_Activity extends CRM_Activity_Form_Activity {
     $this->_fields['source_contact_id']['label'] = ts('Reported By');
     unset($this->_fields['status_id']['attributes']['required']);
 
+    if ($this->restrictAssignmentByUserAccount()) {
+      $assigneeParameters['uf_user'] = 1;
+    }
+
+    $activityAssignmentGroups = $this->getActivityAssignmentGroups();
+    if (!empty($activityAssignmentGroups)) {
+      $assigneeParameters['group'] = ['IN' => $activityAssignmentGroups];
+    }
+
+    if (!empty($assigneeParameters)) {
+      $this->_fields['assignee_contact_id']['attributes']['api']['params']
+        = array_merge($this->_fields['assignee_contact_id']['attributes']['api']['params'], $assigneeParameters);
+
+      $this->_fields['followup_assignee_contact_id']['attributes']['api']['params']
+        = array_merge($this->_fields['followup_assignee_contact_id']['attributes']['api']['params'], $assigneeParameters);
+
+      //Disallow creating a contact from the assignee field UI.
+      $this->_fields['assignee_contact_id']['attributes']['create'] = FALSE;
+      $this->_fields['followup_assignee_contact_id']['attributes']['create'] = FALSE;
+    }
+
     if ($this->_caseType) {
       $xmlProcessor = new CRM_Case_XMLProcessor_Process();
       $aTypes = array();
-      foreach ($this->_caseType as $key => $val) {
+      foreach (array_unique($this->_caseType) as $val) {
         $activityTypes = $xmlProcessor->get($val, 'ActivityTypes', TRUE);
         $aTypes = $aTypes + $activityTypes;
       }
@@ -651,4 +682,64 @@ class CRM_Case_Form_Activity extends CRM_Activity_Form_Activity {
     }
   }
 
+  /**
+   * Returns the groups that contacts must belong to in order to be assigned
+   * an activity for this case. It returns an empty array if no groups are found for
+   * the case type linked to the caseId.
+   *
+   * @return array
+   */
+  private function getActivityAssignmentGroups() {
+    if (!$this->_caseTypeDefinition) {
+      return [];
+    }
+
+    $assignmentGroups = [];
+    foreach ($this->_caseTypeDefinition as $caseId => $definition) {
+      if (!empty($definition['activityAsgmtGrps'])) {
+        $assignmentGroups = array_merge($assignmentGroups, $definition['activityAsgmtGrps']);
+      }
+    }
+
+    return $assignmentGroups;
+  }
+
+  /**
+   * Returns whether contacts must have a user account in order to be
+   * assigned an activity for this case.
+   *
+   * @return bool
+   */
+  private function restrictAssignmentByUserAccount() {
+    if (!$this->_caseTypeDefinition) {
+      return FALSE;
+    }
+
+    foreach ($this->_caseTypeDefinition as $caseId => $definition) {
+      if (!empty($definition['restrictActivityAsgmtToCmsUser'])) {
+        return TRUE;
+      }
+    }
+
+    return FALSE;
+  }
+
+  /**
+   * Returns the case type definition column value for the case type linked to the caseId.
+   *
+   * @return array
+   */
+  private function getCaseTypeDefinition() {
+    if (!$this->_caseId) {
+      return [];
+    }
+
+    $definitions = civicrm_api3('CaseType', 'get', [
+      'return' => ['name', 'definition'],
+      'name' => ['IN' => array_unique($this->_caseType)],
+    ]);
+
+    return array_column($definitions['values'], 'definition', 'name');
+  }
+
 }
index 994c9fb1f06a9e67f9453ec7366a41e4754cdcc8..ab8e2d4c12835d5befc1ebdf02d5443efb9104c6 100644 (file)
       $scope.caseType.definition.caseRoles = $scope.caseType.definition.caseRoles || [];
       $scope.caseType.definition.statuses = $scope.caseType.definition.statuses || [];
       $scope.caseType.definition.timelineActivityTypes = $scope.caseType.definition.timelineActivityTypes || [];
+      $scope.caseType.definition.restrictActivityAsgmtToCmsUser = $scope.caseType.definition.restrictActivityAsgmtToCmsUser || 0;
+      $scope.caseType.definition.activityAsgmtGrps = $scope.caseType.definition.activityAsgmtGrps || [];
 
       _.each($scope.caseType.definition.activitySets, function (set) {
         _.each(set.activityTypes, function (type, name) {
       });
       // Ignore if ALL or NONE selected
       $scope.caseType.definition.statuses = selectedStatuses.length == _.size($scope.selectedStatuses) ? [] : selectedStatuses;
+
+      if ($scope.caseType.definition.activityAsgmtGrps) {
+        $scope.caseType.definition.activityAsgmtGrps = $scope.caseType.definition.activityAsgmtGrps.toString().split(",");
+      }
+
       var result = crmApi('CaseType', 'create', $scope.caseType, true);
       result.then(function(data) {
         if (data.is_error === 0 || data.is_error == '0') {
index 9b121d0f4dd73d89a7936bc023a89b6159c32e06..99f91f3807d903a8632c0ec9593513328b4bcdd7 100644 (file)
@@ -41,5 +41,22 @@ The original form used table layout; don't know if we have an alternative, CSS-b
     <div crm-ui-field="{title: ts('Enabled?')}">
       <input name="is_active" type="checkbox" ng-model="caseType.is_active" ng-true-value="'1'" ng-false-value="'0'"/>
     </div>
+    <div crm-ui-field="{name: 'caseTypeDetailForm.activityAsgmtGrps', title: ts('Restrict Assignment to Groups')}">
+      <input
+        name="activityAsgmtGrps"
+        crm-ui-id="caseTypeDetailForm.activityAsgmtGrps"
+        crm-entityref="{entity: 'Group', api: {params: {is_hidden: 0, is_active: 1}}, select: {allowClear: true, multiple: true, placeholder: ts('Select Group')}}"
+        ng-model="caseType.definition.activityAsgmtGrps"
+      />
+    </div>
+    <div crm-ui-field="{title: ts('Restrict Assignment to Website Users')}">
+      <input
+        name="restrictActivityAsgmtToCmsUser"
+        type="checkbox"
+        ng-model="caseType.definition.restrictActivityAsgmtToCmsUser"
+        ng-true-value="'1'"
+        ng-false-value="'0'"
+      />
+    </div>
   </div>
 </div>