Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dev/core#107: Add default assignee when creating cases #11998

Conversation

reneolivo
Copy link
Contributor

@reneolivo reneolivo commented Apr 19, 2018

Overview

This PR allows admins to configure default assignees for cases. The default assignees can be selected as follows:

  • By relationship to case client.
  • User creating the case.
  • Specific contact.
  • No default assignee.

Before

Configuring the default assignee

screenshot 2018-04-18 22 05 15

Creating a new case

dr barry adams ii housing support hr17 9100 1
No contact assigned to activities.

After

Configuring the default assignee

anim

Creating a new case

anim

Technical Details

Inserting the default assignee options in the database

A new upgrader was added targeting version 5.0.1, a hypothetical version that branches off from 5.0.0, which is a new version in development. The upgrader reads as follows:

public function upgrade_5_0_1($rev) {
  $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);

  // Add option group for activity default assignees:
  CRM_Core_BAO_OptionGroup::ensureOptionGroupExists(array(
    'name' => 'activity_default_assignee',
    'title' => ts('Activity default assignee'),
    'is_reserved' => 1,
  ));

  // Add option values for activity default assignees:
  $options = array(
    array('name' => 'NONE', 'label' => ts('None')),
    array('name' => 'BY_RELATIONSHIP', 'label' => ts('By relationship to case client')),
    array('name' => 'SPECIFIC_CONTACT', 'label' => ts('Specific contact')),
    array('name' => 'USER_CREATING_THE_CASE', 'label' => ts('User creating the case'))
  );

  foreach ($options as $option) {
    CRM_Core_BAO_OptionValue::ensureOptionValueExists(array(
      'option_group_id' => 'activity_default_assignee',
      'name' => $option['name'],
      'label' => $option['label'],
      'is_active' => TRUE
    ));
  }
}

Displaying the default assignee options

The default assignee options are requested in the apiCalls for the CaseTypeCtrl controller:

$routeProvider.when('/caseType/:id', {
  // ...
  controller: 'CaseTypeCtrl',
  resolve: {
    apiCalls: function($route, crmApi) {
      var reqs = {};
      // ...

      reqs.defaultAssigneeTypes = ['OptionValue', 'get', {
        option_group_id: 'activity_default_assignee',
        sequential: 1,
        options: {
          limit: 0
        }
      }];

      // ...
    }
  }
});

crmCaseType.controller('CaseTypeCtrl', function($scope, crmApi, apiCalls) {
  // ...
  $scope.defaultAssigneeTypes = apiCalls.defaultAssigneeTypes.values;
  // this index is used to determine which option was chosen and to display companion fields accordingly:
  $scope.defaultAssigneeTypeValues = _.chain($scope.defaultAssigneeTypes)
        .indexBy('name').mapValues('value').value();
  // ...
});

The fields are displayed in the form by editing the timelineTable.html as this:

<td>
  <select
    ui-jq="select2"
    ui-options="{dropdownAutoWidth : true}"
    ng-model="activity.default_assignee_type"
    ng-options="option.value as option.label for option in defaultAssigneeTypes"
    ng-change="clearActivityDefaultAssigneeValues(activity)"
  ></select>

  <p ng-if="activity.default_assignee_type === defaultAssigneeTypeValues.BY_RELATIONSHIP">
    <select
      ui-jq="select2"
      ui-options="{dropdownAutoWidth : true}"
      ng-model="activity.default_assignee_relationship"
      ng-options="option.id as option.text for option in relationshipTypeOptions"
      required
    ></select>
  </p>

  <p ng-if="activity.default_assignee_type === defaultAssigneeTypeValues.SPECIFIC_CONTACT">
    <input
      type="text"
      ng-model="activity.default_assignee_contact"
      placeholder="- select contact -"
      crm-entityref="{ entity: 'Contact' }"
      data-create-links="true"
      required />
  </p>
</td>

Default assignee for new cases

For new cases the default assignee is set to NONE:

if (apiCalls.caseType) {
  // edit case type
  $scope.caseType = apiCalls.caseType;
} else {
  // new case type
  $scope.caseType = _.cloneDeep(newCaseTypeTemplate);
  $scope.caseType.definition.activitySets[0].activityTypes[0]
    .default_assignee_type = $scope.defaultAssigneeTypeValues.NONE;
}

Selecting the assignee

The default assignee is selected when creating the activity at the CRM_Case_XMLProcessor_Process::createActivity function since this one has most of the information we need to select the assignee:

public function createActivity($activityTypeXML, &$params) {
  // ...
  $activityParams['assignee_contact_id'] = $this->getDefaultAssigneeForActivity($activityParams, $activityTypeXML);
  // ...
}

protected function getDefaultAssigneeForActivity($activityParams, $activityTypeXML) {
  if (!isset($activityTypeXML->default_assignee_type)) {
    return NULL;
  }

  // fetches the default assignee types to see which strategy to choose for the default assignee
  $defaultAssigneeOptionsValues = $this->getDefaultAssigneeOptionValues();

  switch($activityTypeXML->default_assignee_type) {
    case $defaultAssigneeOptionsValues['BY_RELATIONSHIP']:
      return $this->getDefaultAssigneeByRelationship($activityParams, $activityTypeXML);
      break;
    case $defaultAssigneeOptionsValues['SPECIFIC_CONTACT']:
      return $this->getDefaultAssigneeBySpecificContact($activityTypeXML);
      break;
    case $defaultAssigneeOptionsValues['USER_CREATING_THE_CASE']:
      return $activityParams['source_contact_id'];
      break;
    case $defaultAssigneeOptionsValues['NONE']:
    default:
      return NULL;
  }
}

getDefaultAssigneeByRelationship is the strategy for selecting an assignee by the relationship to the target contact:

protected function getDefaultAssigneeByRelationship($activityParams, $activityTypeXML) {
  if (!isset($activityTypeXML->default_assignee_relationship)) {
    return NULL;
  }

  $targetContactId = is_array($activityParams['target_contact_id'])
    ? CRM_Utils_Array::first($activityParams['target_contact_id'])
    : $activityParams['target_contact_id'];

  $relationships = civicrm_api3('Relationship', 'get', [
    'contact_id_b' => $targetContactId,
    'relationship_type_id.name' => $activityTypeXML->default_assignee_relationship,
    'is_active' => 1,
    'sequential' => 1
  ]);

  if ($relationships['count']) {
    return $relationships['values'][0]['contact_id_a'];
  } else {
    return NULL;
  }
}

getDefaultAssigneeBySpecificContact is the strategy when choosing a specific contact. It returns the ID only if the contact exists in case the contact were to be deleted at a later time:

protected function getDefaultAssigneeBySpecificContact($activityTypeXML) {
  if (!$activityTypeXML->default_assignee_contact) {
    return NULL;
  }

  $contact = civicrm_api3('Contact', 'get', [
    'id' => $activityTypeXML->default_assignee_contact
  ]);

  if ($contact['count'] == 1) {
    return $activityTypeXML->default_assignee_contact;
  }

  return NULL;
}

Comments

  • PHP and JS tests were added to cover for the new functionality.
  • Added some missing JS tests for the crmCaseType controller.
  • The CRM_Case_XMLProcessor_Process class was missing a test file so a new was created at:
    tests/phpunit/CRM/Case/XMLProcessor/ProcessTest.php, but only tests related to the default assignee selections were added.
  • CRM_Core_BAO_OptionValue::ensureOptionValueExists had to be enhanced to return the option value id whether it finds the value or creates a new one.

Gitlab Issue:
https://lab.civicrm.org/dev/core/issues/107

@civicrm-builder
Copy link

Can one of the admins verify this patch?

@reneolivo reneolivo force-pushed the PCHR-3410-add-default-assignee-when-creating-cases branch 3 times, most recently from 1ecf8e3 to 299cf39 Compare April 19, 2018 15:50
@reneolivo reneolivo changed the title (WIP) PCHR-3410: Add default assignee when creating cases Add default assignee when creating cases Apr 19, 2018
@mattwire
Copy link
Contributor

@reneolivo Idea looks good. Are you able to squash the commits down from 26 into functional changes? And is there any code that can be pulled into a separate PR to be reviewed/merged first as there is quite a lot here!

@reneolivo
Copy link
Contributor Author

Hello @mattwire squashing is possible of course. Splitting the PR can be a bit tricky though since we could merge an incomplete feature. In the original PR (as seen from the comments) we split the PRs like this:

  • A PR to add the default assignee options and displaying the options on the case configuration.
  • A PR that actually selects the default assignees when creating a case.

We could try to split it that way too, but if only the first one gets approved then no default assignee would be chosen and we'd end up with an incomplete feature.

What do you suggest?

@mattwire
Copy link
Contributor

What do you suggest?

If it does not make sense to separate then that's fine. Squashing a bit should help with review. I just wondered if there was anything that could be picked out, eg bugfixes that are useful even without the feature.

@reneolivo reneolivo force-pushed the PCHR-3410-add-default-assignee-when-creating-cases branch from a9871a3 to 3bedb10 Compare April 19, 2018 21:04
@reneolivo
Copy link
Contributor Author

@mattwire I have sorted and squashed the commits into logical changes.

There were one or two that fix something done in previous commits, but I had to leave them since they fix something that was done over several commit, otherwise I'd have to squash big chunks of changes and it would be harder to review.

Please let me know if this is more manageable.

CRM/Case/XMLProcessor/Process.php Show resolved Hide resolved
CRM/Case/XMLProcessor/Process.php Show resolved Hide resolved
CRM/Core/BAO/OptionValue.php Show resolved Hide resolved
$this->assertActivityAssignedToContactExists($this->assigneeContactId);
}

public function testCreateActivityWithDefaultContactByRelationButTheresNoRelationship() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rename this to testCreateActivityWithDefaultContactByRelationButThereIsNoRelationship ?

CRM/Case/XMLProcessor/Process.php Show resolved Hide resolved
@tunbola
Copy link
Contributor

tunbola commented May 8, 2018

@reneolivo , I think this change would need the user documentation update: https://docs.civicrm.org/user/en/latest/case-management/set-up/
Also can we link this to a Civi Core Issue.

@reneolivo reneolivo changed the title Add default assignee when creating cases dev/core#107 Add default assignee when creating cases May 9, 2018
@reneolivo reneolivo changed the title dev/core#107 Add default assignee when creating cases dev/core#107: Add default assignee when creating cases May 9, 2018
@reneolivo reneolivo force-pushed the PCHR-3410-add-default-assignee-when-creating-cases branch from cea8b81 to 5b1a2f4 Compare May 9, 2018 21:53
@colemanw
Copy link
Member

I'm +1 on this conceptually. I think it's a good feature for CiviCase and doesn't really affect anyone who doesn't need it.

@@ -55,12 +56,41 @@
<td>
<select
ui-jq="select2"
ui-options="{dropdownAutoWidth : true}"
ui-options="{ dropdownAutoWidth: true }"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to leave these as it was. Because civicrm follows no space convention.

*
* @param string $rev
*/
public function upgrade_5_3_alpha1($rev) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should not it be 5_2_alpha1?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be 5.3.alpha1 because that's the version in master.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just needed to move it to another file.

@reneolivo reneolivo force-pushed the PCHR-3410-add-default-assignee-when-creating-cases branch 4 times, most recently from 5885a1a to aa65268 Compare May 10, 2018 21:30
@colemanw
Copy link
Member

@reneolivo please click the "details" button under the test failure indicator to see the code style issues that need fixing.

@colemanw
Copy link
Member

@civicrm-builder retest this please

1 similar comment
@colemanw
Copy link
Member

@civicrm-builder retest this please

@reneolivo
Copy link
Contributor Author

@colemanw can you please check again? I think everything is in order now.

@colemanw
Copy link
Member

@reneolivo I'm testing this out, but merging this would be a lot nicer if the PR had one commit instead of 16. Could you rebase+squash it please?
As a general rule, it's nice to have one feature == one commit. Sometimes having multiple commits in a PR makes sense if they are for distinctly different changes, but in this case this is 16 commits because of WIP.

@colemanw
Copy link
Member

I tested this and it mostly works, but I found problems with the "By relationship" option.

  1. Create a contact with a relationship (Friend of) to another contact.
  2. Create a case type with 2 follow-up activities, one by relationship to "Friend of" and another by relationship to "Spouse of".
  3. Create a case of that type for the new contact.

Expect: 1 followup activity will be assigned to the friend, the other will be assigned to no-one.
Actual: both followup activities are assigned to an unrelated contact.

@reneolivo reneolivo force-pushed the PCHR-3410-add-default-assignee-when-creating-cases branch from 9a15b84 to 994084b Compare May 17, 2018 22:53
@reneolivo reneolivo force-pushed the PCHR-3410-add-default-assignee-when-creating-cases branch from 6d693d0 to 4f54a18 Compare June 28, 2018 11:46
@reneolivo
Copy link
Contributor Author

Hello @colemanw. I have rebased the changes with master and moved the upgrader to FiveFour.php instead of FiveThree.php. Please let me know if everything is in order.

@reneolivo reneolivo force-pushed the PCHR-3410-add-default-assignee-when-creating-cases branch from 4f54a18 to 84f3a24 Compare July 3, 2018 01:50
@colemanw
Copy link
Member

colemanw commented Jul 3, 2018

@civicrm-builder retest this please

@eileenmcnaughton
Copy link
Contributor

@colemanw we would ideally merge this before rc is cut...

@colemanw
Copy link
Member

colemanw commented Jul 4, 2018

I'd like to merge this but there is one more merge conflict showing up in the upgrade file. @reneolivo are you able to fix this? If not I'll get to it when I can.

This feature allows users to define default assignees for each activity in a case type.
When creating a new case contacts are assigned to activities automatically by following
one of these rules:

* By relationship to case client
* The user creating the case
* A specific contact
* None (default)
@reneolivo reneolivo force-pushed the PCHR-3410-add-default-assignee-when-creating-cases branch from 84f3a24 to 68098e7 Compare July 4, 2018 10:46
@reneolivo
Copy link
Contributor Author

@colemanw @eileenmcnaughton fixed the conflicts.

@colemanw colemanw merged commit 66e0102 into civicrm:master Jul 4, 2018
@reneolivo reneolivo deleted the PCHR-3410-add-default-assignee-when-creating-cases branch July 4, 2018 22:30
@reneolivo reneolivo restored the PCHR-3410-add-default-assignee-when-creating-cases branch July 20, 2018 22:33
@reneolivo reneolivo deleted the PCHR-3410-add-default-assignee-when-creating-cases branch July 23, 2018 19:59
reneolivo added a commit to compucorp/civicrm-core that referenced this pull request Jul 24, 2018
reneolivo added a commit to compucorp/civicrm-core that referenced this pull request Jul 24, 2018
reneolivo added a commit to compucorp/civicrm-core that referenced this pull request Jul 24, 2018
davialexandre pushed a commit to compucorp/civicrm-core that referenced this pull request Jul 27, 2018
@eileenmcnaughton
Copy link
Contributor

This PR appears to be causing a fatal error on upgrade https://lab.civicrm.org/dev/core/issues/304

@petednz
Copy link

petednz commented Sep 18, 2018

and still a problem on dmaster - imo either this should not be REQUIRED - or the documentation or some alert needs to show to explain to someone why they cannot Save a Case Type

@totten
Copy link
Member

totten commented Sep 18, 2018

@reneolivo, I agree with @petednz -- it probably shouldn't be required (or, if it is required, then the UI needs to explain better.)

A couple examples of why it shouldn't be required:

  1. From an r-tech perspective, all existing case-types on an upgraded site become unsaveable -- because they don't have this configuration data. If you're upgrading, you'd expect that existing case-types would continue to function.

  2. If you create a new case-type, it prepopulates the standard timeline with an "Open Case" activity. This doesn't have a default assignee -- and, in fact, you don't need an assignee for "Open Case".

screen shot 2018-09-18 at 10 44 39 am

  1. From an r-user perspective, they were previously allowed to have activities with a blank assignee. This could be acceptable if (a) there's only one person doing case-mgmt, (b) the culture of the case-mgmt team encourages joint responsibility/ownership, or (c) the admins want the case-mgrs to be intentional about choosing an assignee.

Aside: I haven't dug in fully yet, but there's a confounding issue -- there's an option-group for assignee policies, but it's only created on upgraded sites... and not on new/clean sites. (See screenshot above.) This could be preventing us from seeing the real/expected behavior.

@totten
Copy link
Member

totten commented Sep 19, 2018

Apologies for the length of my last comment -- it was a bit misdirected under the assumption that the behavior was intended to work that way. After reading/testing more, I can confirm the problem only affects new builds and relates specifically to the option-group. #12842 is the fix for 5.5(stable).

@reneolivo
Copy link
Contributor Author

Hello @petednz and @totten the field is not required per se. It is only required when the user sets the default assignee by relationship. This is important because the backend expects the field to have a value assigned when the the default assignee is set by relationship. Also, it's important to note that for this case, the required field is a dropdown of relationship types, not assignees.

If the workflow needs to be amended even after #12842 please let me know and I can change it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
10 participants