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)
* @copyright CiviCRM LLC (c) 2004-2018
*/
class CRM_Case_XMLProcessor_Process extends CRM_Case_XMLProcessor {
+ protected $defaultAssigneeOptionsValues = [];
+
/**
* Run.
*
/**
* @param SimpleXMLElement $caseTypeXML
+ *
* @return array<string> symbolic activity-type names
*/
public function getDeclaredActivityTypes($caseTypeXML) {
/**
* @param SimpleXMLElement $caseTypeXML
+ *
* @return array<string> symbolic relationship-type names
*/
public function getDeclaredRelationshipTypes($caseTypeXML) {
);
}
+ $activityParams['assignee_contact_id'] = $this->getDefaultAssigneeForActivity($activityParams, $activityTypeXML);
+
//parsing date to default preference format
$params['activity_date_time'] = CRM_Utils_Date::processDate($params['activity_date_time']);
return TRUE;
}
+ /**
+ * Return the default assignee contact for the activity.
+ *
+ * @param array $activityParams
+ * @param object $activityTypeXML
+ *
+ * @return int|null the ID of the default assignee contact or null if none.
+ */
+ protected function getDefaultAssigneeForActivity($activityParams, $activityTypeXML) {
+ if (!isset($activityTypeXML->default_assignee_type)) {
+ return NULL;
+ }
+
+ $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;
+ }
+ }
+
+ /**
+ * Fetches and caches the activity's default assignee options.
+ *
+ * @return array
+ */
+ protected function getDefaultAssigneeOptionValues() {
+ if (!empty($this->defaultAssigneeOptionsValues)) {
+ return $this->defaultAssigneeOptionsValues;
+ }
+
+ $defaultAssigneeOptions = civicrm_api3('OptionValue', 'get', [
+ 'option_group_id' => 'activity_default_assignee',
+ 'options' => [ 'limit' => 0 ]
+ ]);
+
+ foreach ($defaultAssigneeOptions['values'] as $option) {
+ $this->defaultAssigneeOptionsValues[$option['name']] = $option['value'];
+ }
+
+ return $this->defaultAssigneeOptionsValues;
+ }
+
+ /**
+ * Returns the default assignee for the activity by searching for the target's
+ * contact relationship type defined in the activity's details.
+ *
+ * @param array $activityParams
+ * @param object $activityTypeXML
+ *
+ * @return int|null the ID of the default assignee contact or null if none.
+ */
+ 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_b_a' => (string) $activityTypeXML->default_assignee_relationship,
+ 'is_active' => 1,
+ 'sequential' => 1,
+ ]);
+
+ if ($relationships['count']) {
+ return $relationships['values'][0]['contact_id_a'];
+ }
+ else {
+ return NULL;
+ }
+ }
+
+ /**
+ * Returns the activity's default assignee for a specific contact if the contact exists,
+ * otherwise returns null.
+ *
+ * @param object $activityTypeXML
+ *
+ * @return int|null
+ */
+ 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;
+ }
+
/**
* @param $activitySetsXML
*
/**
* @param string $caseType
+ *
* @return array<\Civi\CCase\CaseChangeListener>
*/
public function getListeners($caseType) {
* @param string $settingKey
* @param string $xmlTag
* @param mixed $default
+ *
* @return int
*/
private function getBoolSetting($settingKey, $xmlTag, $default = 0) {
* that an option value exists, without hitting an error if it already exists.
*
* This is sympathetic to sites who might pre-add it.
+ *
+ * @param array $params the option value attributes.
+ * @return array the option value attributes.
*/
public static function ensureOptionValueExists($params) {
- $existingValues = civicrm_api3('OptionValue', 'get', array(
+ $result = civicrm_api3('OptionValue', 'get', array(
'option_group_id' => $params['option_group_id'],
'name' => $params['name'],
- 'return' => 'id',
+ 'return' => ['id', 'value'],
+ 'sequential' => 1,
));
- if (!$existingValues['count']) {
- civicrm_api3('OptionValue', 'create', $params);
+
+ if (!$result['count']) {
+ $result = civicrm_api3('OptionValue', 'create', $params);
}
+
+ return CRM_Utils_Array::first($result['values']);
}
}
'civicrm_uf_group', 'add_cancel_button', "tinyint DEFAULT '1' COMMENT 'Should a Cancel button be included in this Profile form.'");
$this->addTask('Add location_id if missing to group_contact table (affects some older installs CRM-20711)', 'addColumn',
'civicrm_group_contact', 'location_id', "int(10) unsigned DEFAULT NULL COMMENT 'Optional location to associate with this membership'");
+ $this->addTask('dev/core#107 - Add Activity\'s default assignee options', 'addActivityDefaultAssigneeOptions');
+ }
+
+ /**
+ * This task adds the default assignee option values that can be selected when
+ * creating or editing a new workflow's activity.
+ *
+ * @return bool
+ */
+ public static function addActivityDefaultAssigneeOptions() {
+ // 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'), 'is_default' => 1),
+ 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_default' => CRM_Utils_Array::value('is_default', $option, 0),
+ 'is_active' => TRUE,
+ ));
+ }
+
+ return TRUE;
}
/*
limit: 0
}
}];
+ reqs.defaultAssigneeTypes = ['OptionValue', 'get', {
+ option_group_id: 'activity_default_assignee',
+ sequential: 1,
+ options: {
+ limit: 0
+ }
+ }];
reqs.relTypes = ['RelationshipType', 'get', {
sequential: 1,
options: {
});
crmCaseType.controller('CaseTypeCtrl', function($scope, crmApi, apiCalls) {
- // CRM_Case_XMLProcessor::REL_TYPE_CNAME
- var REL_TYPE_CNAME = CRM.crmCaseType.REL_TYPE_CNAME,
-
- ts = $scope.ts = CRM.ts(null);
+ var REL_TYPE_CNAME, defaultAssigneeDefaultValue, ts;
+
+ (function init () {
+ // CRM_Case_XMLProcessor::REL_TYPE_CNAME
+ REL_TYPE_CNAME = CRM.crmCaseType.REL_TYPE_CNAME;
+
+ ts = $scope.ts = CRM.ts(null);
+ $scope.locks = { caseTypeName: true, activitySetName: true };
+ $scope.workflows = { timeline: 'Timeline', sequence: 'Sequence' };
+ defaultAssigneeDefaultValue = _.find(apiCalls.defaultAssigneeTypes.values, { is_default: '1' }) || {};
+
+ storeApiCallsResults();
+ initCaseType();
+ initCaseTypeDefinition();
+ initSelectedStatuses();
+ })();
+
+ /// Stores the api calls results in the $scope object
+ function storeApiCallsResults() {
+ $scope.activityStatuses = apiCalls.actStatuses.values;
+ $scope.caseStatuses = _.indexBy(apiCalls.caseStatuses.values, 'name');
+ $scope.activityTypes = _.indexBy(apiCalls.actTypes.values, 'name');
+ $scope.activityTypeOptions = _.map(apiCalls.actTypes.values, formatActivityTypeOption);
+ $scope.defaultAssigneeTypes = apiCalls.defaultAssigneeTypes.values;
+ $scope.relationshipTypeOptions = _.map(apiCalls.relTypes.values, function(type) {
+ return {id: type[REL_TYPE_CNAME], text: type.label_b_a};
+ });
+ // stores the default assignee values indexed by their option name:
+ $scope.defaultAssigneeTypeValues = _.chain($scope.defaultAssigneeTypes)
+ .indexBy('name').mapValues('value').value();
+ }
- $scope.activityStatuses = apiCalls.actStatuses.values;
- $scope.caseStatuses = _.indexBy(apiCalls.caseStatuses.values, 'name');
- $scope.activityTypes = _.indexBy(apiCalls.actTypes.values, 'name');
- $scope.activityTypeOptions = _.map(apiCalls.actTypes.values, formatActivityTypeOption);
- $scope.relationshipTypeOptions = _.map(apiCalls.relTypes.values, function(type) {
- return {id: type[REL_TYPE_CNAME], text: type.label_b_a};
- });
- $scope.locks = {caseTypeName: true, activitySetName: true};
+ /// initializes the case type object
+ function initCaseType() {
+ var isNewCaseType = !apiCalls.caseType;
- $scope.workflows = {
- 'timeline': 'Timeline',
- 'sequence': 'Sequence'
- };
+ if (isNewCaseType) {
+ $scope.caseType = _.cloneDeep(newCaseTypeTemplate);
+ } else {
+ $scope.caseType = apiCalls.caseType;
+ }
+ }
- $scope.caseType = apiCalls.caseType ? apiCalls.caseType : _.cloneDeep(newCaseTypeTemplate);
- $scope.caseType.definition = $scope.caseType.definition || [];
- $scope.caseType.definition.activityTypes = $scope.caseType.definition.activityTypes || [];
- $scope.caseType.definition.activitySets = $scope.caseType.definition.activitySets || [];
- _.each($scope.caseType.definition.activitySets, function (set) {
- _.each(set.activityTypes, function (type, name) {
- type.label = $scope.activityTypes[type.name].label;
+ /// initializes the case type definition object
+ function initCaseTypeDefinition() {
+ $scope.caseType.definition = $scope.caseType.definition || [];
+ $scope.caseType.definition.activityTypes = $scope.caseType.definition.activityTypes || [];
+ $scope.caseType.definition.activitySets = $scope.caseType.definition.activitySets || [];
+ $scope.caseType.definition.caseRoles = $scope.caseType.definition.caseRoles || [];
+ $scope.caseType.definition.statuses = $scope.caseType.definition.statuses || [];
+ $scope.caseType.definition.timelineActivityTypes = $scope.caseType.definition.timelineActivityTypes || [];
+
+ _.each($scope.caseType.definition.activitySets, function (set) {
+ _.each(set.activityTypes, function (type, name) {
+ var isDefaultAssigneeTypeUndefined = _.isUndefined(type.default_assignee_type);
+ type.label = $scope.activityTypes[type.name].label;
+
+ if (isDefaultAssigneeTypeUndefined) {
+ type.default_assignee_type = defaultAssigneeDefaultValue.value;
+ }
+ });
});
- });
- $scope.caseType.definition.caseRoles = $scope.caseType.definition.caseRoles || [];
- $scope.caseType.definition.statuses = $scope.caseType.definition.statuses || [];
+ }
- $scope.caseType.definition.timelineActivityTypes = $scope.caseType.definition.timelineActivityTypes || [];
+ /// initializes the selected statuses
+ function initSelectedStatuses() {
+ $scope.selectedStatuses = {};
- $scope.selectedStatuses = {};
- _.each(apiCalls.caseStatuses.values, function (status) {
- $scope.selectedStatuses[status.name] = !$scope.caseType.definition.statuses.length || $scope.caseType.definition.statuses.indexOf(status.name) > -1;
- });
+ _.each(apiCalls.caseStatuses.values, function (status) {
+ $scope.selectedStatuses[status.name] = !$scope.caseType.definition.statuses.length || $scope.caseType.definition.statuses.indexOf(status.name) > -1;
+ });
+ }
$scope.addActivitySet = function(workflow) {
var activitySet = {};
status: 'Scheduled',
reference_activity: 'Open Case',
reference_offset: '1',
- reference_select: 'newest'
+ reference_select: 'newest',
+ default_assignee_type: $scope.defaultAssigneeTypeValues.NONE
};
activitySet.activityTypes.push(activity);
if(typeof activitySet.timeline !== "undefined" && activitySet.timeline == "1") {
}
};
+ /// Clears the activity's default assignee values for relationship and contact
+ $scope.clearActivityDefaultAssigneeValues = function(activity) {
+ activity.default_assignee_relationship = null;
+ activity.default_assignee_contact = null;
+ };
+
/// Add a new role
$scope.addRole = function(roles, roleName) {
var names = _.pluck($scope.caseType.definition.caseRoles, 'name');
<th>{{ts('Reference')}}</th>
<th>{{ts('Offset')}}</th>
<th>{{ts('Select')}}</th>
+ <th>{{ts('Default assignee')}}</th>
<th></th>
</tr>
</thead>
<i class="crm-i fa-arrows grip-n-drag"></i>
</td>
<td>
- <i class="crm-i {{ activityTypes[activity.name].icon }}"></i>
- {{ activity.label }}
+ <i class="crm-i {{activityTypes[activity.name].icon}}"></i>
+ {{activity.label}}
</td>
<td>
<select
ui-jq="select2"
- ui-options="{dropdownAutoWidth : true}"
+ ui-options="{dropdownAutoWidth: true}"
ng-model="activity.status"
ng-options="actStatus.name as actStatus.label for actStatus in activityStatuses|orderBy:'label'"
>
<td>
<select
ui-jq="select2"
- ui-options="{dropdownAutoWidth : true}"
+ ui-options="{dropdownAutoWidth: true}"
ng-model="activity.reference_activity"
ng-options="activityType.name as activityType.label for activityType in caseType.definition.timelineActivityTypes"
>
<td>
<select
ui-jq="select2"
- ui-options="{dropdownAutoWidth : true}"
+ ui-options="{dropdownAutoWidth: true}"
ng-model="activity.reference_select"
ng-options="key as value for (key,value) in {newest: ts('Newest'), oldest: ts('Oldest')}"
>
</select>
</td>
+ <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>
<td>
<a class="crm-hover-button"
crm-icon="fa-trash"
<tfoot>
<tr class="addRow">
- <td colspan="6">
+ <td colspan="8">
<span crm-add-name=""
crm-options="activityTypeOptions"
crm-var="newActivity"
var apiCalls;
var ctrl;
var compile;
+ var defaultAssigneeDefaultValue;
var scope;
beforeEach(function() {
}
]
}
+ },
+ defaultAssigneeTypes: {
+ values: [
+ {
+ "id": "1174",
+ "option_group_id": "152",
+ "label": "None",
+ "value": "1",
+ "name": "NONE",
+ "filter": "0",
+ "is_default": "1",
+ "weight": "1",
+ "is_optgroup": "0",
+ "is_reserved": "0",
+ "is_active": "1"
+ },
+ {
+ "id": "1175",
+ "option_group_id": "152",
+ "label": "By relationship to workflow client",
+ "value": "2",
+ "name": "BY_RELATIONSHIP",
+ "filter": "0",
+ "is_default": "0",
+ "weight": "2",
+ "is_optgroup": "0",
+ "is_reserved": "0",
+ "is_active": "1"
+ },
+ {
+ "id": "1176",
+ "option_group_id": "152",
+ "label": "Specific contact",
+ "value": "3",
+ "name": "SPECIFIC_CONTACT",
+ "filter": "0",
+ "is_default": "0",
+ "weight": "3",
+ "is_optgroup": "0",
+ "is_reserved": "0",
+ "is_active": "1"
+ },
+ {
+ "id": "1177",
+ "option_group_id": "152",
+ "label": "User creating the workflow",
+ "value": "4",
+ "name": "USER_CREATING_THE_CASE",
+ "filter": "0",
+ "is_default": "0",
+ "weight": "4",
+ "is_optgroup": "0",
+ "is_reserved": "0",
+ "is_active": "1"
+ }
+ ]
}
};
+ defaultAssigneeDefaultValue = _.find(apiCalls.defaultAssigneeTypes.values, { is_default: '1' });
scope = $rootScope.$new();
ctrl = $controller('CaseTypeCtrl', {$scope: scope, apiCalls: apiCalls});
});
expect(scope.activityTypes['ADC referral']).toEqualData(apiCalls.actTypes.values[0]);
});
+ it('should store the default assignee types', function() {
+ expect(scope.defaultAssigneeTypes).toBe(apiCalls.defaultAssigneeTypes.values);
+ });
+
+ it('should store the default assignee types values indexed by name', function() {
+ var defaultAssigneeTypeValues = _.chain(apiCalls.defaultAssigneeTypes.values)
+ .indexBy('name').mapValues('value').value();
+
+ expect(scope.defaultAssigneeTypeValues).toEqual(defaultAssigneeTypeValues);
+ });
+
it('addActivitySet should add an activitySet to the case type', function() {
scope.addActivitySet('timeline');
var activitySets = scope.caseType.definition.activitySets;
expect(newSet.timeline).toBe('1');
expect(newSet.label).toBe('Timeline #2');
});
+
+ describe('when clearing the activity\'s default assignee type values', function() {
+ var activity;
+
+ beforeEach(function() {
+ activity = {
+ default_assignee_relationship: 1,
+ default_assignee_contact: 2
+ };
+
+ scope.clearActivityDefaultAssigneeValues(activity);
+ });
+
+ it('clears the default assignee relationship for the activity', function() {
+ expect(activity.default_assignee_relationship).toBe(null);
+ });
+
+ it('clears the default assignee contact for the activity', function() {
+ expect(activity.default_assignee_contact).toBe(null);
+ });
+ });
+
+ describe('when adding a new activity to a set', function() {
+ var activitySet;
+
+ beforeEach(function() {
+ activitySet = { activityTypes: [] };
+ scope.activityTypes = { comment: { label: 'Add a new comment' } };
+
+ scope.addActivity(activitySet, 'comment');
+ });
+
+ it('adds a new Comment activity to the set', function() {
+ expect(activitySet.activityTypes[0]).toEqual({
+ name: 'comment',
+ label: scope.activityTypes.comment.label,
+ status: 'Scheduled',
+ reference_activity: 'Open Case',
+ reference_offset: '1',
+ reference_select: 'newest',
+ default_assignee_type: defaultAssigneeDefaultValue.value
+ });
+ });
+ });
+
+ describe('when creating a new workflow', function() {
+ beforeEach(inject(function ($controller) {
+ apiCalls.caseType = null;
+
+ ctrl = $controller('CaseTypeCtrl', {$scope: scope, apiCalls: apiCalls});
+ }));
+
+ it('sets default values for the case type title, name, and active status', function() {
+ expect(scope.caseType).toEqual(jasmine.objectContaining({
+ title: '',
+ name: '',
+ is_active: '1'
+ }));
+ });
+
+ it('adds an Open Case activty to the default activty set', function() {
+ expect(scope.caseType.definition.activitySets[0].activityTypes).toEqual([{
+ name: 'Open Case',
+ label: 'Open Case',
+ status: 'Completed',
+ default_assignee_type: defaultAssigneeDefaultValue.value
+ }]);
+ });
+ });
});
describe('crmAddName', function () {
--- /dev/null
+<?php
+require_once 'CiviTest/CiviCaseTestCase.php';
+
+/**
+ * Class CRM_Case_PseudoConstantTest
+ * @group headless
+ */
+class CRM_Case_XMLProcessor_ProcessTest extends CiviCaseTestCase {
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->defaultAssigneeOptionsValues = [];
+ $this->assigneeContactId = $this->individualCreate();
+ $this->targetContactId = $this->individualCreate();
+
+ $this->setUpDefaultAssigneeOptions();
+ $this->setUpRelationship();
+
+ $activityTypeXml = '<activity-type><name>Open Case</name></activity-type>';
+ $this->activityTypeXml = new SimpleXMLElement($activityTypeXml);
+ $this->params = [
+ 'activity_date_time' => date('Ymd'),
+ 'caseID' => $this->caseTypeId,
+ 'clientID' => $this->targetContactId,
+ 'creatorID' => $this->_loggedInUser,
+ ];
+
+ $this->process = new CRM_Case_XMLProcessor_Process();
+ }
+
+ /**
+ * Adds the default assignee group and options to the test database.
+ * It also stores the IDs of the options in an index.
+ */
+ protected function setUpDefaultAssigneeOptions() {
+ $options = [
+ 'NONE', 'BY_RELATIONSHIP', 'SPECIFIC_CONTACT', 'USER_CREATING_THE_CASE'
+ ];
+
+ CRM_Core_BAO_OptionGroup::ensureOptionGroupExists([
+ 'name' => 'activity_default_assignee'
+ ]);
+
+ foreach ($options as $option) {
+ $optionValue = CRM_Core_BAO_OptionValue::ensureOptionValueExists([
+ 'option_group_id' => 'activity_default_assignee',
+ 'name' => $option,
+ 'label' => $option
+ ]);
+
+ $this->defaultAssigneeOptionsValues[$option] = $optionValue['value'];
+ }
+ }
+
+ /**
+ * Adds a relationship between the activity's target contact and default assignee.
+ */
+ protected function setUpRelationship() {
+ $this->assignedRelationshipType = 'Instructor of';
+ $this->unassignedRelationshipType = 'Employer of';
+
+ $assignedRelationshipTypeId = $this->relationshipTypeCreate([
+ 'contact_type_a' => 'Individual',
+ 'contact_type_b' => 'Individual',
+ 'name_a_b' => 'Pupil of',
+ 'name_b_a' => $this->assignedRelationshipType,
+ ]);
+ $this->relationshipTypeCreate([
+ 'name_a_b' => 'Employee of',
+ 'name_b_a' => $this->unassignedRelationshipType,
+ ]);
+ $this->callAPISuccess('Relationship', 'create', [
+ 'contact_id_a' => $this->assigneeContactId,
+ 'contact_id_b' => $this->targetContactId,
+ 'relationship_type_id' => $assignedRelationshipTypeId
+ ]);
+ }
+
+ /**
+ * Tests the creation of activities with default assignee by relationship.
+ */
+ public function testCreateActivityWithDefaultContactByRelationship() {
+ $this->activityTypeXml->default_assignee_type = $this->defaultAssigneeOptionsValues['BY_RELATIONSHIP'];
+ $this->activityTypeXml->default_assignee_relationship = $this->assignedRelationshipType;
+
+ $this->process->createActivity($this->activityTypeXml, $this->params);
+ $this->assertActivityAssignedToContactExists($this->assigneeContactId);
+ }
+
+ /**
+ * Tests the creation of activities with default assignee by relationship,
+ * but the target contact doesn't have any relationship of the selected type.
+ */
+ public function testCreateActivityWithDefaultContactByRelationButTheresNoRelationship() {
+ $this->activityTypeXml->default_assignee_type = $this->defaultAssigneeOptionsValues['BY_RELATIONSHIP'];
+ $this->activityTypeXml->default_assignee_relationship = $this->unassignedRelationshipType;
+
+ $this->process->createActivity($this->activityTypeXml, $this->params);
+ $this->assertActivityAssignedToContactExists(NULL);
+ }
+
+ /**
+ * Tests the creation of activities with default assignee set to a specific contact.
+ */
+ public function testCreateActivityAssignedToSpecificContact() {
+ $this->activityTypeXml->default_assignee_type = $this->defaultAssigneeOptionsValues['SPECIFIC_CONTACT'];
+ $this->activityTypeXml->default_assignee_contact = $this->assigneeContactId;
+
+ $this->process->createActivity($this->activityTypeXml, $this->params);
+ $this->assertActivityAssignedToContactExists($this->assigneeContactId);
+ }
+
+ /**
+ * Tests the creation of activities with default assignee set to a specific contact,
+ * but the contact does not exist.
+ */
+ public function testCreateActivityAssignedToNonExistantSpecificContact() {
+ $this->activityTypeXml->default_assignee_type = $this->defaultAssigneeOptionsValues['SPECIFIC_CONTACT'];
+ $this->activityTypeXml->default_assignee_contact = 987456321;
+
+ $this->process->createActivity($this->activityTypeXml, $this->params);
+ $this->assertActivityAssignedToContactExists(NULL);
+ }
+
+ /**
+ * Tests the creation of activities with the default assignee being the one
+ * creating the case's activity.
+ */
+ public function testCreateActivityAssignedToUserCreatingTheCase() {
+ $this->activityTypeXml->default_assignee_type = $this->defaultAssigneeOptionsValues['USER_CREATING_THE_CASE'];
+
+ $this->process->createActivity($this->activityTypeXml, $this->params);
+ $this->assertActivityAssignedToContactExists($this->_loggedInUser);
+ }
+
+ /**
+ * Tests the creation of activities when the default assignee is set to NONE.
+ */
+ public function testCreateActivityAssignedNoUser() {
+ $this->activityTypeXml->default_assignee_type = $this->defaultAssigneeOptionsValues['NONE'];
+
+ $this->process->createActivity($this->activityTypeXml, $this->params);
+ $this->assertActivityAssignedToContactExists(NULL);
+ }
+
+ /**
+ * Tests the creation of activities when the default assignee is set to NONE.
+ */
+ public function testCreateActivityWithNoDefaultAssigneeOption() {
+ $this->process->createActivity($this->activityTypeXml, $this->params);
+ $this->assertActivityAssignedToContactExists(NULL);
+ }
+
+ /**
+ * Asserts that an activity was created where the assignee was the one related
+ * to the target contact.
+ *
+ * @param int|null $assigneeContactId the ID of the expected assigned contact or NULL if expected to be empty.
+ */
+ protected function assertActivityAssignedToContactExists($assigneeContactId) {
+ $expectedContact = $assigneeContactId === NULL ? [] : [$assigneeContactId];
+ $result = $this->callAPISuccess('Activity', 'get', [
+ 'target_contact_id' => $this->targetContactId,
+ 'return' => ['assignee_contact_id']
+ ]);
+ $activity = CRM_Utils_Array::first($result['values']);
+
+ $this->assertNotNull($activity, 'Target contact has no activities assigned to them');
+ $this->assertEquals($expectedContact, $activity['assignee_contact_id'], 'Activity is not assigned to expected contact');
+ }
+
+}
* decision to disable it & leaving it in that state.
*/
public function testEnsureOptionValueExistsDisabled() {
- CRM_Core_BAO_OptionValue::ensureOptionValueExists(array('name' => 'Crashed', 'option_group_id' => 'contribution_status', 'is_active' => 0));
+ $optionValue = CRM_Core_BAO_OptionValue::ensureOptionValueExists(array('name' => 'Crashed', 'option_group_id' => 'contribution_status', 'is_active' => 0));
$value = $this->callAPISuccessGetSingle('OptionValue', array('name' => 'Crashed', 'option_group_id' => 'contribution_status'));
$this->assertEquals(0, $value['is_active']);
- CRM_Core_BAO_OptionValue::ensureOptionValueExists(array('name' => 'Crashed', 'option_group_id' => 'contribution_status'));
+ $this->assertEquals($value['id'], $optionValue['id']);
+
+ $optionValue = CRM_Core_BAO_OptionValue::ensureOptionValueExists(array('name' => 'Crashed', 'option_group_id' => 'contribution_status'));
$value = $this->callAPISuccessGetSingle('OptionValue', array('name' => 'Crashed', 'option_group_id' => 'contribution_status'));
$this->assertEquals(0, $value['is_active']);
+ $this->assertEquals($value['id'], $optionValue['id']);
}
}