* API result array
*/
function civicrm_api3_activity_create($params) {
+ $isNew = empty($params['id']);
if (empty($params['id'])) {
// an update does not require any mandatory parameters
}
if (!empty($params['case_id'])) {
$case_id = $params['case_id'];
- if (!empty($params['id'])) {
+ if (!empty($params['id']) && Civi::settings()->get('civicaseActivityRevisions')) {
$oldActivityParams = array('id' => $params['id']);
if (!$oldActivityValues) {
CRM_Activity_BAO_Activity::retrieve($oldActivityParams, $oldActivityValues);
$activityBAO = CRM_Activity_BAO_Activity::create($params);
if (isset($activityBAO->id)) {
- if ($case_id && !$createRevision) {
- // If this is a brand new case activity we need to add this
- $caseActivityParams = array('activity_id' => $activityBAO->id, 'case_id' => $case_id);
- CRM_Case_BAO_Case::processCaseActivity($caseActivityParams);
+ if ($case_id && $isNew && !$createRevision) {
+ // If this is a brand new case activity, add to case(s)
+ foreach ((array) $case_id as $singleCaseId) {
+ $caseActivityParams = array('activity_id' => $activityBAO->id, 'case_id' => $singleCaseId);
+ CRM_Case_BAO_Case::processCaseActivity($caseActivityParams);
+ }
}
_civicrm_api3_object_to_array($activityBAO, $activityArray[$activityBAO->id]);
$params['tag_id'] = array(
'title' => 'Tags',
'description' => 'Find activities with specified tags.',
- 'type' => 1,
+ 'type' => CRM_Utils_Type::T_INT,
'FKClassName' => 'CRM_Core_DAO_Tag',
'FKApiName' => 'Tag',
'supports_joins' => TRUE,
$params['file_id'] = array(
'title' => 'Attached Files',
'description' => 'Find activities with attached files.',
- 'type' => 1,
+ 'type' => CRM_Utils_Type::T_INT,
'FKClassName' => 'CRM_Core_DAO_File',
'FKApiName' => 'File',
);
$params['case_id'] = array(
'title' => 'Cases',
'description' => 'Find activities within specified cases.',
- 'type' => 1,
+ 'type' => CRM_Utils_Type::T_INT,
'FKClassName' => 'CRM_Case_DAO_Case',
'FKApiName' => 'Case',
);
$params['contact_id'] = array(
'title' => 'Activity Contact ID',
'description' => 'Find activities involving this contact (as target, source, OR assignee).',
- 'type' => 1,
+ 'type' => CRM_Utils_Type::T_INT,
'FKClassName' => 'CRM_Contact_DAO_Contact',
'FKApiName' => 'Contact',
);
$params['target_contact_id'] = array(
'title' => 'Target Contact ID',
'description' => 'Find activities with specified target contact.',
- 'type' => 1,
+ 'type' => CRM_Utils_Type::T_INT,
'FKClassName' => 'CRM_Contact_DAO_Contact',
'FKApiName' => 'Contact',
);
$params['source_contact_id'] = array(
'title' => 'Source Contact ID',
'description' => 'Find activities with specified source contact.',
- 'type' => 1,
+ 'type' => CRM_Utils_Type::T_INT,
'FKClassName' => 'CRM_Contact_DAO_Contact',
'FKApiName' => 'Contact',
);
$params['assignee_contact_id'] = array(
'title' => 'Assignee Contact ID',
'description' => 'Find activities with specified assignee contact.',
- 'type' => 1,
+ 'type' => CRM_Utils_Type::T_INT,
'FKClassName' => 'CRM_Contact_DAO_Contact',
'FKApiName' => 'Contact',
);
+ $params['is_overdue'] = array(
+ 'title' => 'Is Activity Overdue',
+ 'description' => 'Incomplete activities with a past date.',
+ 'type' => CRM_Utils_Type::T_BOOLEAN,
+ );
}
/**
* @throws \Civi\API\Exception\UnauthorizedException
*/
function civicrm_api3_activity_get($params) {
-
+ $options = _civicrm_api3_get_options_from_params($params, FALSE, 'Activity', 'get');
$sql = CRM_Utils_SQL_Select::fragment();
- $recordTypes = civicrm_api3('ActivityContact', 'getoptions', array('field' => 'record_type_id'));
- $recordTypes = $recordTypes['values'];
- $activityContactOptions = array(
- 'contact_id' => NULL,
- 'target_contact_id' => array_search('Activity Targets', $recordTypes),
- 'source_contact_id' => array_search('Activity Source', $recordTypes),
- 'assignee_contact_id' => array_search('Activity Assignees', $recordTypes),
- );
+
if (empty($params['target_contact_id']) && empty($params['source_contact_id'])
&& empty($params['assignee_contact_id']) &&
!empty($params['check_permissions']) && !CRM_Core_Permission::check('view all activities')
//$params['contact_id'] = array('IS NOT NULL' => TRUE);
}
- foreach ($activityContactOptions as $activityContactName => $activityContactValue) {
- if (!empty($params[$activityContactName])) {
- if (!is_array($params[$activityContactName])) {
- $params[$activityContactName] = array('=' => $params[$activityContactName]);
+ _civicrm_api3_activity_get_extraFilters($params, $sql);
+
+ // Handle is_overdue sort
+ if (!empty($options['sort'])) {
+ $sort = explode(', ', $options['sort']);
+
+ foreach ($sort as $index => &$sortString) {
+ // Get sort field and direction
+ list($sortField, $dir) = array_pad(explode(' ', $sortString), 2, 'ASC');
+ if ($sortField == 'is_overdue') {
+ $incomplete = implode(',', array_keys(CRM_Activity_BAO_Activity::getStatusesByType(CRM_Activity_BAO_Activity::INCOMPLETE)));
+ $sql->orderBy("IF((a.activity_date_time >= NOW() OR a.status_id NOT IN ($incomplete)), 0, 1) $dir", NULL, $index);
+ // Replace the sort with a placeholder which will be ignored by sql
+ $sortString = '(1)';
}
- $clause = \CRM_Core_DAO::createSQLFilter('contact_id', $params[$activityContactName]);
- $typeClause = $activityContactValue ? 'record_type_id = #typeId AND ' : '';
- $sql->where("a.id IN (SELECT activity_id FROM civicrm_activity_contact WHERE $typeClause !clause)",
- array('#typeId' => $activityContactValue, '!clause' => $clause)
- );
- }
- }
- if (!empty($params['tag_id'])) {
- if (!is_array($params['tag_id'])) {
- $params['tag_id'] = array('=' => $params['tag_id']);
- }
- $clause = \CRM_Core_DAO::createSQLFilter('tag_id', $params['tag_id']);
- if ($clause) {
- $sql->where('a.id IN (SELECT entity_id FROM civicrm_entity_tag WHERE entity_table = "civicrm_activity" AND !clause)', array('!clause' => $clause));
}
+ $params['options']['sort'] = implode(', ', $sort);
}
- if (!empty($params['file_id'])) {
- if (!is_array($params['file_id'])) {
- $params['file_id'] = array('=' => $params['file_id']);
- }
- $clause = \CRM_Core_DAO::createSQLFilter('file_id', $params['file_id']);
- if ($clause) {
- $sql->where('a.id IN (SELECT entity_id FROM civicrm_entity_file WHERE entity_table = "civicrm_activity" AND !clause)', array('!clause' => $clause));
- }
- }
- if (!empty($params['case_id'])) {
- if (!is_array($params['case_id'])) {
- $params['case_id'] = array('=' => $params['case_id']);
- }
- $clause = \CRM_Core_DAO::createSQLFilter('case_id', $params['case_id']);
- if ($clause) {
- $sql->where('a.id IN (SELECT activity_id FROM civicrm_case_activity WHERE !clause)', array('!clause' => $clause));
- }
+
+ // Ensure there's enough data for calculating is_overdue
+ if (!empty($options['return']['is_overdue']) && (empty($options['return']['status_id']) || empty($options['return']['activity_date_time']))) {
+ $options['return']['status_id'] = $options['return']['activity_date_time'] = 1;
+ $params['return'] = array_keys($options['return']);
}
+
$activities = _civicrm_api3_basic_get(_civicrm_api3_get_BAO(__FUNCTION__), $params, FALSE, 'Activity', $sql);
if (!empty($params['check_permissions']) && !CRM_Core_Permission::check('view all activities')) {
// @todo get this to work at the query level - see contact_id join above.
}
}
}
- $options = _civicrm_api3_get_options_from_params($params, FALSE, 'Activity', 'get');
if ($options['is_count']) {
return civicrm_api3_create_success($activities, $params, 'Activity', 'get');
}
return civicrm_api3_create_success($activities, $params, 'Activity', 'get');
}
+/**
+ * Support filters beyond what basic_get can do.
+ *
+ * @param array $params
+ * @param CRM_Utils_SQL_Select $sql
+ * @throws \CiviCRM_API3_Exception
+ * @throws \Exception
+ */
+function _civicrm_api3_activity_get_extraFilters(&$params, &$sql) {
+ // Filter by activity contacts
+ $recordTypes = civicrm_api3('ActivityContact', 'getoptions', array('field' => 'record_type_id'));
+ $recordTypes = $recordTypes['values'];
+ $activityContactOptions = array(
+ 'contact_id' => NULL,
+ 'target_contact_id' => array_search('Activity Targets', $recordTypes),
+ 'source_contact_id' => array_search('Activity Source', $recordTypes),
+ 'assignee_contact_id' => array_search('Activity Assignees', $recordTypes),
+ );
+ foreach ($activityContactOptions as $activityContactName => $activityContactValue) {
+ if (!empty($params[$activityContactName])) {
+ if (!is_array($params[$activityContactName])) {
+ $params[$activityContactName] = array('=' => $params[$activityContactName]);
+ }
+ $clause = \CRM_Core_DAO::createSQLFilter('contact_id', $params[$activityContactName]);
+ $typeClause = $activityContactValue ? 'record_type_id = #typeId AND ' : '';
+ $sql->where("a.id IN (SELECT activity_id FROM civicrm_activity_contact WHERE $typeClause !clause)",
+ array('#typeId' => $activityContactValue, '!clause' => $clause)
+ );
+ }
+ }
+
+ // Handle is_overdue filter
+ // Boolean calculated field - does not support operators
+ if (isset($params['is_overdue'])) {
+ $incomplete = implode(',', array_keys(CRM_Activity_BAO_Activity::getStatusesByType(CRM_Activity_BAO_Activity::INCOMPLETE)));
+ if ($params['is_overdue']) {
+ $sql->where('a.activity_date_time < NOW()');
+ $sql->where("a.status_id IN ($incomplete)");
+ }
+ else {
+ $sql->where("(a.activity_date_time >= NOW() OR a.status_id NOT IN ($incomplete))");
+ }
+ }
+
+ // Define how to handle filters on some related entities.
+ // Subqueries are nice in (a) avoiding duplicates and (b) when the result
+ // list is expected to be bite-sized. Joins are nice (a) with larger
+ // datasets and (b) checking for non-existent relations.
+ $rels = array(
+ 'tag_id' => array(
+ 'subquery' => 'a.id IN (SELECT entity_id FROM civicrm_entity_tag WHERE entity_table = "civicrm_activity" AND !clause)',
+ 'join' => '!joinType civicrm_entity_tag !alias ON (!alias.entity_table = "civicrm_activity" AND !alias.entity_id = a.id)',
+ 'column' => 'tag_id',
+ ),
+ 'file_id' => array(
+ 'subquery' => 'a.id IN (SELECT entity_id FROM civicrm_entity_file WHERE entity_table = "civicrm_activity" AND !clause)',
+ 'join' => '!joinType civicrm_entity_file !alias ON (!alias.entity_table = "civicrm_activity" AND !alias.entity_id = a.id)',
+ 'column' => 'file_id',
+ ),
+ 'case_id' => array(
+ 'subquery' => 'a.id IN (SELECT activity_id FROM civicrm_case_activity WHERE !clause)',
+ 'join' => '!joinType civicrm_case_activity !alias ON (!alias.activity_id = a.id)',
+ 'column' => 'case_id',
+ ),
+ );
+ foreach ($rels as $filter => $relSpec) {
+ if (!empty($params[$filter])) {
+ if (!is_array($params[$filter])) {
+ $params[$filter] = array('=' => $params[$filter]);
+ }
+ // $mode is one of ('LEFT JOIN', 'INNER JOIN', 'SUBQUERY')
+ $mode = isset($params[$filter]['IS NULL']) ? 'LEFT JOIN' : 'SUBQUERY';
+ if ($mode === 'SUBQUERY') {
+ $clause = \CRM_Core_DAO::createSQLFilter($relSpec['column'], $params[$filter]);
+ if ($clause) {
+ $sql->where($relSpec['subquery'], array('!clause' => $clause));
+ }
+ }
+ else {
+ $alias = 'actjoin_' . $filter;
+ $clause = \CRM_Core_DAO::createSQLFilter($alias . "." . $relSpec['column'], $params[$filter]);
+ if ($clause) {
+ $sql->join($alias, $relSpec['join'], array('!alias' => $alias, 'joinType' => $mode));
+ $sql->where($clause);
+ }
+ }
+ }
+ }
+}
+
/**
* Given a list of activities, append any extra data requested about the activities.
*
$dao = CRM_Core_DAO::executeQuery("SELECT activity_id, case_id FROM civicrm_case_activity WHERE activity_id IN (%1)",
array(1 => array(implode(',', array_keys($activities)), 'String', CRM_Core_DAO::QUERY_FORMAT_NO_QUOTES)));
while ($dao->fetch()) {
- $activities[$dao->activity_id]['case_id'] = $dao->case_id;
+ $activities[$dao->activity_id]['case_id'][] = $dao->case_id;
+ }
+ break;
+
+ case 'is_overdue':
+ foreach ($activities as $key => $activityArray) {
+ $activities[$key]['is_overdue'] = (int) CRM_Activity_BAO_Activity::isOverdue($activityArray);
}
break;