foreach ($caseRelationships as $key => $value) {
// This role has been filled
- unset($caseRoles[$value['relation_type']]);
+ unset($caseRoles[$value['relation_type'] . '_' . $value['relationship_direction']]);
// mark original case relationships record to use on setting edit links below
$caseRelationships[$key]['source'] = 'caseRel';
}
foreach ($caseRelationships as $key => &$row) {
$typeLabel = $row['relation'];
// Add "<br />(Case Manager)" to label
- if (!empty($row['relation_type']) && $row['relation_type'] == $managerRoleId) {
+ if (!empty($row['relation_type']) && !empty($row['relationship_direction']) && $row['relation_type'] . '_' . $row['relationship_direction'] == $managerRoleId) {
$row['relation'] .= '<br />' . '(' . ts('Case Manager') . ')';
}
// view user links
'civicrm_case.status_id as case_status_id',
't_act.status_id as status_id',
'civicrm_case.start_date as case_start_date',
- 'case_relation_type.label_b_a as case_role',
+ "GROUP_CONCAT(DISTINCT IF(case_relationship.contact_id_b = $userID, case_relation_type.label_a_b, case_relation_type.label_b_a) SEPARATOR ', ') as case_role",
't_act.activity_date_time as activity_date_time',
't_act.id as activity_id',
);
ON civicrm_phone.contact_id = civicrm_contact.id
AND civicrm_phone.is_primary = 1
LEFT JOIN civicrm_relationship case_relationship
- ON case_relationship.contact_id_a = civicrm_case_contact.contact_id
- AND case_relationship.contact_id_b = {$userID}
+ ON ((case_relationship.contact_id_a = civicrm_case_contact.contact_id AND case_relationship.contact_id_b = {$userID})
+ OR (case_relationship.contact_id_b = civicrm_case_contact.contact_id AND case_relationship.contact_id_a = {$userID}))
AND case_relationship.is_active
AND case_relationship.case_id = civicrm_case.id
LEFT JOIN civicrm_relationship_type case_relation_type
$whereClauses = array('civicrm_case.is_deleted = 0 AND civicrm_contact.is_deleted <> 1');
if (!$allCases) {
- $whereClauses[] .= " case_relationship.contact_id_b = {$userID} AND case_relationship.is_active ";
+ $whereClauses[] = "(case_relationship.contact_id_b = {$userID} OR case_relationship.contact_id_a = {$userID})";
+ $whereClauses[] = 'case_relationship.is_active';
}
if (empty($params['status_id']) && ($type == 'upcoming' || $type == 'any')) {
- $whereClauses[] = " civicrm_case.status_id != " . CRM_Core_PseudoConstant::getKey('CRM_Case_BAO_Case', 'case_status_id', 'Closed');
+ $whereClauses[] = "civicrm_case.status_id != " . CRM_Core_PseudoConstant::getKey('CRM_Case_BAO_Case', 'case_status_id', 'Closed');
}
foreach (array('case_type_id', 'status_id') as $column) {
// build rows with actual data
$rows = array();
- $myGroupByClause = $mySelectClause = $myCaseFromClause = $myCaseWhereClause = '';
+ $myGroupByClause = $mySelectClause = $myCaseFromClause = $myCaseWhereClauseA = $myCaseWhereClauseB = '';
if ($allCases) {
$userID = 'null';
$all = 1;
$case_owner = 1;
- $myGroupByClause = ' GROUP BY civicrm_case.id';
+ $myGroupByClauseB = ' GROUP BY civicrm_case.id';
}
else {
$all = 0;
$case_owner = 2;
- $myCaseWhereClause = " AND case_relationship.contact_id_b = {$userID} AND case_relationship.is_active ";
- $myGroupByClause = " GROUP BY CONCAT(case_relationship.case_id,'-',case_relationship.contact_id_b)";
+ $myCaseWhereClauseA = " AND case_relationship.contact_id_a = {$userID} AND case_relationship.is_active ";
+ $myGroupByClauseA = " GROUP BY CONCAT(civicrm_case.id,'-',case_relationship.contact_id_a)";
+ $myCaseWhereClauseB = " AND case_relationship.contact_id_b = {$userID} AND case_relationship.is_active ";
+ $myGroupByClauseB = " GROUP BY CONCAT(civicrm_case.id,'-',case_relationship.contact_id_b)";
}
- $myGroupByClause .= ", case_status.label, status_id, case_type_id";
-
+ $myGroupByClauseB .= ", case_status.label, status_id, case_type_id, civicrm_case.id";
+ $myGroupByClauseA = $myGroupByClauseB;
// FIXME: This query could be a lot more efficient if it used COUNT() instead of returning all rows and then counting them with php
$query = "
-SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS case_type,
- case_type_id, case_relationship.contact_id_b
+SELECT civicrm_case.id, case_status.label AS case_status, status_id, civicrm_case_type.title AS case_type,
+ case_type_id, case_relationship.contact_id_b as case_contact
FROM civicrm_case
INNER JOIN civicrm_case_contact cc on cc.case_id = civicrm_case.id
LEFT JOIN civicrm_case_type ON civicrm_case.case_type_id = civicrm_case_type.id
LEFT JOIN civicrm_relationship case_relationship ON ( case_relationship.case_id = civicrm_case.id
AND case_relationship.contact_id_b = {$userID} AND case_relationship.is_active )
WHERE is_deleted = 0 AND cc.contact_id IN (SELECT id FROM civicrm_contact WHERE is_deleted <> 1)
-{$myCaseWhereClause} {$myGroupByClause}";
+{$myCaseWhereClauseB} {$myGroupByClauseB}
+UNION
+SELECT civicrm_case.id, case_status.label AS case_status, status_id, civicrm_case_type.title AS case_type,
+ case_type_id, case_relationship.contact_id_a as case_contact
+ FROM civicrm_case
+ INNER JOIN civicrm_case_contact cc on cc.case_id = civicrm_case.id
+ LEFT JOIN civicrm_case_type ON civicrm_case.case_type_id = civicrm_case_type.id
+ LEFT JOIN civicrm_option_group option_group_case_status ON ( option_group_case_status.name = 'case_status' )
+ LEFT JOIN civicrm_option_value case_status ON ( civicrm_case.status_id = case_status.value
+ AND option_group_case_status.id = case_status.option_group_id )
+ LEFT JOIN civicrm_relationship case_relationship ON ( case_relationship.case_id = civicrm_case.id
+ AND case_relationship.contact_id_a = {$userID})
+ WHERE is_deleted = 0 AND cc.contact_id IN (SELECT id FROM civicrm_contact WHERE is_deleted <> 1)
+{$myCaseWhereClauseA} {$myGroupByClauseA}";
$res = CRM_Core_DAO::executeQuery($query);
while ($res->fetch()) {
$caseInfo = civicrm_api3('Case', 'getsingle', array(
'id' => $caseID,
// Most efficient way of retrieving definition is to also include case type id and name so the api doesn't have to look it up separately
- 'return' => array('case_type_id', 'case_type_id.name', 'case_type_id.definition'),
+ 'return' => array('case_type_id', 'case_type_id.name', 'case_type_id.definition', 'contact_id'),
));
if (!empty($caseInfo['case_type_id.definition']['caseRoles'])) {
$caseRoles = CRM_Utils_Array::rekey($caseInfo['case_type_id.definition']['caseRoles'], 'name');
}
}
- $values = array();
- $query = '
- SELECT cc.display_name as name, cc.sort_name as sort_name, cc.id, cr.relationship_type_id, crt.label_b_a as role, crt.name_b_a, ce.email, cp.phone
- FROM civicrm_relationship cr
- LEFT JOIN civicrm_relationship_type crt
- ON crt.id = cr.relationship_type_id
- LEFT JOIN civicrm_contact cc
- ON cc.id = cr.contact_id_b
- LEFT JOIN civicrm_email ce
- ON ce.contact_id = cc.id
- AND ce.is_primary= 1
- LEFT JOIN civicrm_phone cp
- ON cp.contact_id = cc.id
- AND cp.is_primary= 1
- WHERE cr.case_id = %1 AND cr.is_active AND cc.is_deleted <> 1';
- $params = array(1 => array($caseID, 'Integer'));
+ $values = array();
+ $query = <<<HERESQL
+ SELECT cc.display_name as name, cc.sort_name as sort_name, cc.id, cr.relationship_type_id, crt.label_b_a as role, crt.name_b_a as role_name, ce.email, cp.phone
+ FROM civicrm_relationship cr
+ JOIN civicrm_relationship_type crt
+ ON crt.id = cr.relationship_type_id
+ JOIN civicrm_contact cc
+ ON cc.id = cr.contact_id_a
+ AND cc.is_deleted <> 1
+ LEFT JOIN civicrm_email ce
+ ON ce.contact_id = cc.id
+ AND ce.is_primary= 1
+ LEFT JOIN civicrm_phone cp
+ ON cp.contact_id = cc.id
+ AND cp.is_primary= 1
+ WHERE cr.case_id = %1
+ AND cr.is_active
+ AND cc.id NOT IN (%2)
+ UNION
+ SELECT cc.display_name as name, cc.sort_name as sort_name, cc.id, cr.relationship_type_id, crt.label_a_b as role, crt.name_a_b as role_name, ce.email, cp.phone
+ FROM civicrm_relationship cr
+ JOIN civicrm_relationship_type crt
+ ON crt.id = cr.relationship_type_id
+ JOIN civicrm_contact cc
+ ON cc.id = cr.contact_id_b
+ AND cc.is_deleted <> 1
+ LEFT JOIN civicrm_email ce
+ ON ce.contact_id = cc.id
+ AND ce.is_primary= 1
+ LEFT JOIN civicrm_phone cp
+ ON cp.contact_id = cc.id
+ AND cp.is_primary= 1
+ WHERE cr.case_id = %1
+ AND cr.is_active
+ AND cc.id NOT IN (%2)
+HERESQL;
+ $params = array(
+ 1 => array($caseID, 'Integer'),
+ 2 => array(implode(',', $caseInfo['client_id']), 'String'),
+ );
$dao = CRM_Core_DAO::executeQuery($query, $params);
while ($dao->fetch()) {
'phone' => $dao->phone,
);
// Add more info about the role (creator, manager)
- $role = CRM_Utils_Array::value($dao->name_b_a, $caseRoles);
+ $role = CRM_Utils_Array::value($dao->role_name, $caseRoles);
if ($role) {
unset($role['name']);
$details += $role;
$managerRoleId = $xmlProcessor->getCaseManagerRoleId($caseType);
if (!empty($managerRoleId)) {
- $managerRoleQuery = "
-SELECT civicrm_contact.id as casemanager_id,
- civicrm_contact.sort_name as casemanager
- FROM civicrm_contact
- LEFT JOIN civicrm_relationship ON (civicrm_relationship.contact_id_b = civicrm_contact.id AND civicrm_relationship.relationship_type_id = %1) AND civicrm_relationship.is_active
- LEFT JOIN civicrm_case ON civicrm_case.id = civicrm_relationship.case_id
- WHERE civicrm_case.id = %2 AND is_active = 1";
+ if (substr($managerRoleId, -4) == '_a_b') {
+ $managerRoleQuery = "
+ SELECT civicrm_contact.id as casemanager_id,
+ civicrm_contact.sort_name as casemanager
+ FROM civicrm_contact
+ LEFT JOIN civicrm_relationship ON (civicrm_relationship.contact_id_b = civicrm_contact.id AND civicrm_relationship.relationship_type_id = %1) AND civicrm_relationship.is_active
+ LEFT JOIN civicrm_case ON civicrm_case.id = civicrm_relationship.case_id
+ WHERE civicrm_case.id = %2 AND is_active = 1";
+ }
+ if (substr($managerRoleId, -4) == '_b_a') {
+ $managerRoleQuery = "
+ SELECT civicrm_contact.id as casemanager_id,
+ civicrm_contact.sort_name as casemanager
+ FROM civicrm_contact
+ LEFT JOIN civicrm_relationship ON (civicrm_relationship.contact_id_a = civicrm_contact.id AND civicrm_relationship.relationship_type_id = %1) AND civicrm_relationship.is_active
+ LEFT JOIN civicrm_case ON civicrm_case.id = civicrm_relationship.case_id
+ WHERE civicrm_case.id = %2 AND is_active = 1";
+ }
$managerRoleParams = array(
- 1 => array($managerRoleId, 'Integer'),
+ 1 => array(substr($managerRoleId, 0, -4), 'Integer'),
2 => array($caseId, 'Integer'),
);
return $filters;
}
+ /**
+ * Fetch Case Role direction from Case Type
+ */
+ public static function getCaseRoleDirection($caseId, $roleTypeId = NULL) {
+ try {
+ $case = civicrm_api3('Case', 'getsingle', array('id' => $caseId));
+ }
+ catch (CiviCRM_API3_Exception $e) {
+ // Lack of permissions will throw an exception
+ return 0;
+ }
+ if (!empty($case['case_type_id'])) {
+ try {
+ $caseType = civicrm_api3('CaseType', 'getsingle', array('id' => $case['case_type_id'], 'return' => array('definition')));
+ }
+ catch (CiviCRM_API3_Exception $e) {
+ // Lack of permissions will throw an exception
+ return 'no case type found';
+ }
+ if (!empty($caseType['definition']['caseRoles'])) {
+ $caseRoles = array();
+ foreach ($caseType['definition']['caseRoles'] as $key => $roleDetails) {
+ // Check if its an a_b label
+ try {
+ $relType = civicrm_api3('RelationshipType', 'getsingle', array('label_a_b' => $roleDetails['name']));
+ }
+ catch (CiviCRM_API3_Exception $e) {
+ }
+ if (!empty($relType['id'])) {
+ $roleDetails['id'] = $relType['id'];
+ $roleDetails['direction'] = 'b_a';
+ }
+ // Check if its a b_a label
+ try {
+ $relTypeBa = civicrm_api3('RelationshipType', 'getsingle', array('label_b_a' => $roleDetails['name']));
+ }
+ catch (CiviCRM_API3_Exception $e) {
+ }
+ if (!empty($relTypeBa['id'])) {
+ if (!empty($roleDetails['direction'])) {
+ $roleDetails['direction'] = 'bidrectional';
+ }
+ else {
+ $roleDetails['id'] = $relTypeBa['id'];
+ $roleDetails['direction'] = 'a_b';
+ }
+ }
+ $caseRoles[$roleDetails['id']] = $roleDetails;
+ }
+ }
+ return $caseRoles;
+ }
+ }
+
}
}
if (!empty($query->_returnProperties['case_role'])) {
- $query->_select['case_role'] = "case_relation_type.label_b_a as case_role";
+ $query->_select['case_role'] = "IF(case_relationship.contact_id_b = contact_a.id, case_relation_type.label_b_a, case_relation_type.label_a_b) as case_role";
$query->_element['case_role'] = 1;
$query->_tables['case_relationship'] = $query->_whereTables['case_relationship'] = 1;
$query->_tables['case_relation_type'] = $query->_whereTables['case_relation_type'] = 1;
if ($value == 2) {
$session = CRM_Core_Session::singleton();
$userID = $session->get('userID');
- $query->_where[$grouping][] = ' ( ' . CRM_Contact_BAO_Query::buildClause("case_relationship.contact_id_b", $op, $userID, 'Int') . ' AND ' . CRM_Contact_BAO_Query::buildClause("case_relationship.is_active", '<>', 0, 'Int') . ' ) ';
+ $query->_where[$grouping][] = ' (( ' . CRM_Contact_BAO_Query::buildClause("case_relationship.contact_id_b", $op, $userID, 'Int') . ' AND ' . CRM_Contact_BAO_Query::buildClause("case_relationship.is_active", '<>', 0, 'Int') . ' ) OR ( ' . CRM_Contact_BAO_Query::buildClause("case_relationship.contact_id_a", $op, $userID, 'Int') . ' AND ' . CRM_Contact_BAO_Query::buildClause("case_relationship.is_active", '<>', 0, 'Int') . ' ))';
$query->_qill[$grouping][] = ts('Case %1 My Cases', [1 => $op]);
$query->_tables['case_relationship'] = $query->_whereTables['case_relationship'] = 1;
}
// adding where clause for case_role
case 'case_role':
- $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_relation_type.name_b_a", $op, $value, 'String');
$query->_qill[$grouping][] = ts("Role in Case %1 '%2'", [1 => $op, 2 => $value]);
$query->_tables['case_relation_type'] = $query->_whereTables['case_relationship_type'] = 1;
$query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1;
case 'case_relationship':
$session = CRM_Core_Session::singleton();
$userID = $session->get('userID');
- $from .= " $side JOIN civicrm_relationship case_relationship ON ( case_relationship.contact_id_a = civicrm_case_contact.contact_id AND case_relationship.contact_id_b = {$userID} AND case_relationship.case_id = civicrm_case.id )";
+ $from .= " $side JOIN civicrm_relationship case_relationship ON ( case_relationship.contact_id_a = civicrm_case_contact.contact_id AND case_relationship.contact_id_b = {$userID} AND case_relationship.case_id = civicrm_case.id OR case_relationship.contact_id_b = civicrm_case_contact.contact_id AND case_relationship.contact_id_a = {$userID} AND case_relationship.case_id = civicrm_case.id )";
break;
case 'case_relation_type':
$contacts = $this->_contactIds;
$clients = CRM_Case_BAO_Case::getCaseClients($caseId);
+ $caseRole = CRM_Case_BAO_Case::getCaseRoleDirection($caseId, $roleTypeId);
$params = [
- 'contact_id_a' => $clients[0],
- 'contact_id_b' => $contacts,
'case_id' => $caseId,
'relationship_type_id' => $roleTypeId,
];
- CRM_Contact_BAO_Relationship::createMultiple($params, 'a');
+ if ($caseRole[$roleTypeId]['direction'] == 'b_a') {
+ $params['contact_id_b'] = $clients[0];
+ $params['contact_id_a'] = $contacts;
+ CRM_Contact_BAO_Relationship::createMultiple($params, 'b');
+ }
+ elseif ($caseRole[$roleTypeId]['direction'] == 'a_b' || $caseRole[$roleTypeId]['direction'] = 'bidirectional') {
+ $params['contact_id_a'] = $clients[0];
+ $params['contact_id_b'] = $contacts;
+ CRM_Contact_BAO_Relationship::createMultiple($params, 'a');
+ }
$url = CRM_Utils_System::url(
'civicrm/contact/view/case',
foreach ($caseRelationships as $key => & $value) {
if (!empty($managerRoleId)) {
- if ($managerRoleId == $value['relation_type']) {
+ if (substr($managerRoleId, 0, -4) == $value['relation_type'] && substr($managerRoleId, -3) == $value['relationship_direction']) {
$value['relation'] = $managerLabel;
}
}
}
elseif ($dao instanceof CRM_Contact_DAO_RelationshipType) {
/** @var $dao CRM_Contact_DAO_RelationshipType */
- $count = CRM_Case_XMLRepository::singleton()
- ->getRelationshipReferenceCount($dao->{CRM_Case_XMLProcessor::REL_TYPE_CNAME});
+
+ // Need to look both directions, but no need to translate case role
+ // direction from XML perspective to client-based perspective
+ $xmlRepo = CRM_Case_XMLRepository::singleton();
+ $count = $xmlRepo->getRelationshipReferenceCount($dao->label_a_b);
+ if ($dao->label_a_b != $dao->label_b_a) {
+ $count += $xmlRepo->getRelationshipReferenceCount($dao->label_b_a);
+ }
if ($count > 0) {
$result[] = [
'name' => 'casetypexml:relationships',
if (!isset(Civi::$statics[__CLASS__]['reltypes'])) {
$relationshipInfo = CRM_Core_PseudoConstant::relationshipType('label', TRUE, NULL);
- Civi::$statics[__CLASS__]['reltypes'] = CRM_Utils_Array::collect(CRM_Case_XMLProcessor::REL_TYPE_CNAME, $relationshipInfo);
+ foreach ($relationshipInfo as $id => $relTypeDetails) {
+ Civi::$statics[__CLASS__]['reltypes']["{$id}_a_b"] = $relTypeDetails['label_a_b'];
+ if ($relTypeDetails['label_a_b'] != $relTypeDetails['label_b_a']) {
+ Civi::$statics[__CLASS__]['reltypes']["{$id}_b_a"] = $relTypeDetails['label_b_a'];
+ }
+ }
}
$validRelTypes = Civi::$statics[__CLASS__]['reltypes'];
$relTypes = $xmlRepo->getAllDeclaredRelationshipTypes();
foreach ($relTypes as $relType) {
+ // Making assumption that client is the A side of the relationship.
+ // Relationship label coming from XML, meaning from perspective of
+ // non-client.
+
+ // These assumptions only apply if a case type is introduced without the
+ // relationship types already existing.
$managed = [
'module' => 'civicrm',
'name' => "civicase:rel:$relType",
'label_a_b' => "$relType is",
'label_b_a' => $relType,
'description' => $relType,
- 'contact_type_a' => 'Individual',
- 'contact_type_b' => 'Individual',
+ 'contact_type_a' => NULL,
+ 'contact_type_b' => NULL,
'contact_sub_type_a' => NULL,
'contact_sub_type_b' => NULL,
],
*/
public static $activityTypes = NULL;
- /**
- * FIXME: This does *NOT* belong in a static property, but we're too late in
- * the 4.5-cycle to do the necessary cleanup.
- *
- * Format is array(int $id => string $relTypeCname).
- *
- * @var array|null
- */
- public static $relationshipTypes = NULL;
-
- /**
- * Relationship-types have four name fields (name_a_b, name_b_a, label_a_b,
- * label_b_a), but CiviCase XML refers to reltypes by a single name.
- * REL_TYPE_CNAME identifies the canonical name field as used by CiviCase XML.
- *
- * This appears to be "label_b_a", but IMHO "name_b_a" would be more
- * sensible.
- */
- const REL_TYPE_CNAME = 'label_b_a';
-
/**
* @param $caseType
*
}
/**
+ * Get all relationship type labels
+ *
+ * TODO: These should probably be names, but under legacy behavior this has
+ * been labels.
+ *
+ * @param bool $fromXML
+ * Is this to be used for lookup of values from XML?
+ * Relationships are recorded in XML from the perspective of the non-client
+ * while relationships in the UI and everywhere else are from the
+ * perspective of the client. Since the XML can't be expected to be
+ * switched, the direction needs to be translated.
* @return array
*/
- public function &allRelationshipTypes() {
- if (self::$relationshipTypes === NULL) {
+ public function &allRelationshipTypes($fromXML = FALSE) {
+ if (!isset(Civi::$statics[__CLASS__]['reltypes'][$fromXML])) {
$relationshipInfo = CRM_Core_PseudoConstant::relationshipType('label', TRUE);
- self::$relationshipTypes = [];
+ Civi::$statics[__CLASS__]['reltypes'][$fromXML] = [];
foreach ($relationshipInfo as $id => $info) {
- self::$relationshipTypes[$id] = $info[CRM_Case_XMLProcessor::REL_TYPE_CNAME];
+ Civi::$statics[__CLASS__]['reltypes'][$fromXML][$id . '_b_a'] = ($fromXML) ? $info['label_a_b'] : $info['label_b_a'];
+ if ($info['label_b_a'] !== $info['label_a_b']) {
+ Civi::$statics[__CLASS__]['reltypes'][$fromXML][$id . '_a_b'] = ($fromXML) ? $info['label_b_a'] : $info['label_a_b'];
+ }
}
}
- return self::$relationshipTypes;
+ return Civi::$statics[__CLASS__]['reltypes'][$fromXML];
}
/**
*/
public static function flushStaticCaches() {
self::$activityTypes = NULL;
- self::$relationshipTypes = NULL;
+ unset(Civi::$statics[__CLASS__]['reltypes']);
}
}
* @return array|mixed
*/
public function &caseRoles($caseRolesXML, $isCaseManager = FALSE) {
- $relationshipTypes = &$this->allRelationshipTypes();
+ // Look up relationship types according to the XML convention (described
+ // from perspective of non-client) but return the labels according to the UI
+ // convention (described from perspective of client)
+ $relationshipTypes = &$this->allRelationshipTypes(TRUE);
+ $relationshipTypesToReturn = &$this->allRelationshipTypes(FALSE);
$result = [];
foreach ($caseRolesXML as $caseRoleXML) {
}
if (!$isCaseManager) {
- $result[$relationshipTypeID] = $relationshipTypeName;
+ $result[$relationshipTypeID] = $relationshipTypesToReturn[$relationshipTypeID];
}
elseif ($relationshipTypeXML->manager == 1) {
return $relationshipTypeID;
* @throws Exception
*/
public function createRelationships($relationshipTypeName, &$params) {
- $relationshipTypes = &$this->allRelationshipTypes();
- // get the relationship id
- $relationshipTypeID = array_search($relationshipTypeName, $relationshipTypes);
+ // The relationshipTypeName is coming from XML, so the argument should be
+ // `TRUE`
+ $relationshipTypes = &$this->allRelationshipTypes(TRUE);
+ // get the relationship
+ $relationshipType = array_search($relationshipTypeName, $relationshipTypes);
- if ($relationshipTypeID === FALSE) {
+ if ($relationshipType === FALSE) {
$docLink = CRM_Utils_System::docURL2("user/case-management/set-up");
CRM_Core_Error::fatal(ts('Relationship type %1, found in case configuration file, is not present in the database %2',
[1 => $relationshipTypeName, 2 => $docLink]
foreach ($client as $key => $clientId) {
$relationshipParams = [
- 'relationship_type_id' => $relationshipTypeID,
- 'contact_id_a' => $clientId,
- 'contact_id_b' => $params['creatorID'],
+ 'relationship_type_id' => substr($relationshipType, 0, -4),
'is_active' => 1,
'case_id' => $params['caseID'],
'start_date' => date("Ymd"),
'end_date' => CRM_Utils_Array::value('relationship_end_date', $params),
];
+ if (substr($relationshipType, -4) == '_b_a') {
+ $relationshipParams['contact_id_b'] = $clientId;
+ $relationshipParams['contact_id_a'] = $params['creatorID'];
+ }
+ if (substr($relationshipType, -4) == '_a_b') {
+ $relationshipParams['contact_id_a'] = $clientId;
+ $relationshipParams['contact_id_b'] = $params['creatorID'];
+ }
+
if (!$this->createRelationship($relationshipParams)) {
CRM_Core_Error::fatal();
return FALSE;
}
/**
+ * Relationships are straight from XML, described from perspective of non-client
+ *
* @param SimpleXMLElement $caseTypeXML
*
* @return array<string> symbolic relationship-type names
$xmlProcessor = new CRM_Case_XMLProcessor_Process();
$caseRoles = $xmlProcessor->get($caseType, 'CaseRoles');
foreach ($caseRelationships as $key => & $value) {
- if (!empty($caseRoles[$value['relation_type']])) {
- unset($caseRoles[$value['relation_type']]);
+ if (!empty($caseRoles[$value['relation_type'] . '_' . $value['relationship_direction']])) {
+ unset($caseRoles[$value['relation_type'] . '_' . $value['relationship_direction']]);
}
if ($isRedact) {
if (!array_key_exists($value['name'], $report->_redactionStringRules)) {
}
/**
+ * Relationships are straight from XML, described from perspective of non-client
+ *
* @return array<string> symbolic-names of relationship-types
*/
public function getAllDeclaredRelationshipTypes() {
if ($fieldName == 'duration') {
$select[] = "IF({$table['fields']['end_date']['dbAlias']} Is Null, '', DATEDIFF({$table['fields']['end_date']['dbAlias']}, {$table['fields']['start_date']['dbAlias']})) as {$tableName}_{$fieldName}";
}
+ elseif ($tableName == 'civicrm_relationship_type') {
+ $select[] = " IF(contact_civireport.id = relationship_civireport.contact_id_a, relationship_type_civireport.label_b_a, relationship_type_civireport.label_a_b) as civicrm_relationship_type_label_b_a";
+ }
else {
$select[] = "{$field['dbAlias']} as {$tableName}_{$fieldName}";
}
if ($this->_relField) {
$this->_from = "
FROM civicrm_contact $c
-inner join civicrm_relationship $cr on {$c}.id = ${cr}.contact_id_b
+inner join civicrm_relationship $cr on {$c}.id = ${cr}.contact_id_b OR {$c}.id = ${cr}.contact_id_a
inner join civicrm_case $cc on ${cc}.id = ${cr}.case_id
inner join civicrm_relationship_type $crt on ${crt}.id=${cr}.relationship_type_id
inner join civicrm_case_contact $ccc on ${ccc}.case_id = ${cc}.id
public function where() {
$clauses = [];
+ if (!empty($this->_params['fields']['label_b_a']) && $this->_params['fields']['label_b_a'] == 1) {
+ $clauses[] = 'contact_civireport.sort_name != c2_civireport.sort_name';
+ }
$this->_having = '';
foreach ($this->_columns as $tableName => $table) {
if (array_key_exists('filters', $table)) {
// ODDITY: This only loads if CiviCase is active.
-CRM_Core_Resources::singleton()->addSetting([
- 'crmCaseType' => [
- 'REL_TYPE_CNAME' => CRM_Case_XMLProcessor::REL_TYPE_CNAME,
- ],
-]);
-
return [
'ext' => 'civicrm',
'js' => ['ang/crmCaseType.js'],
sequential: 1,
is_active: 1,
options: {
- sort: CRM.crmCaseType.REL_TYPE_CNAME,
+ sort: 'label_a_b',
limit: 0
}
}];
});
crmCaseType.controller('CaseTypeCtrl', function($scope, crmApi, apiCalls, crmUiHelp) {
- var REL_TYPE_CNAME, defaultAssigneeDefaultValue, ts;
+ var 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.hs = crmUiHelp({file: 'CRM/Case/CaseType'});
$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};
- });
- $scope.defaultRelationshipTypeOptions = getDefaultRelationshipTypeOptions();
+ $scope.relationshipTypeOptions = getRelationshipTypeOptions(false);
+ $scope.defaultRelationshipTypeOptions = getRelationshipTypeOptions(true);
// stores the default assignee values indexed by their option name:
$scope.defaultAssigneeTypeValues = _.chain($scope.defaultAssigneeTypes)
.indexBy('name').mapValues('value').value();
}
- /// Returns the default relationship type options. If the relationship is
- /// bidirectional (Ex: Spouse of) it adds a single option otherwise it adds
- /// two options representing the relationship type directions
- /// (Ex: Employee of, Employer is)
- function getDefaultRelationshipTypeOptions() {
+ // Returns the relationship type options. If the relationship is
+ // bidirectional (Ex: Spouse of) it adds a single option otherwise it adds
+ // two options representing the relationship type directions (Ex: Employee
+ // of, Employer of).
+ //
+ // The default relationship field needs values that are IDs with direction,
+ // while the role field needs values that are names (with implicit
+ // direction).
+ //
+ // At any rate, the labels should follow the convention in the UI of
+ // describing case roles from the perspective of the client, while the
+ // values must follow the convention in the XML of describing case roles
+ // from the perspective of the non-client.
+ function getRelationshipTypeOptions($isDefault) {
return _.transform(apiCalls.relTypes.values, function(result, relType) {
var isBidirectionalRelationship = relType.label_a_b === relType.label_b_a;
-
- result.push({
- label: relType.label_b_a,
- value: relType.id + '_b_a'
- });
-
- if (!isBidirectionalRelationship) {
+ if ($isDefault) {
result.push({
- label: relType.label_a_b,
+ label: relType.label_b_a,
value: relType.id + '_a_b'
});
+
+ if (!isBidirectionalRelationship) {
+ result.push({
+ label: relType.label_a_b,
+ value: relType.id + '_b_a'
+ });
+ }
+ }
+ // TODO The ids below really should use names not labels see
+ // https://lab.civicrm.org/dev/core/issues/774
+ else {
+ result.push({
+ text: relType.label_b_a,
+ id: relType.label_a_b
+ });
+
+ if (!isBidirectionalRelationship) {
+ result.push({
+ text: relType.label_a_b,
+ id: relType.label_b_a
+ });
+ }
}
}, []);
}
}
});
});
+
+ // go lookup and add client-perspective labels for $scope.caseType.definition.caseRoles
+ _.each($scope.caseType.definition.caseRoles, function (set) {
+ _.each($scope.relationshipTypeOptions, function (relTypes) {
+ if (relTypes.text == set.name) {
+ set.displaylabel = relTypes.id;
+ }
+ });
+ });
}
/// initializes the selected statuses
activity.default_assignee_contact = null;
};
+ // TODO roleName passed to addRole is a misnomer, its passed as the
+ // label HOWEVER it should be saved to xml as the name see
+ // https://lab.civicrm.org/dev/core/issues/774
+
/// Add a new role
$scope.addRole = function(roles, roleName) {
var names = _.pluck($scope.caseType.definition.caseRoles, 'name');
if (!_.contains(names, roleName)) {
- if (_.where($scope.relationshipTypeOptions, {id: roleName}).length) {
- roles.push({name: roleName});
+ var matchingRoles = _.filter($scope.relationshipTypeOptions, {id: roleName});
+ if (matchingRoles.length) {
+ var matchingRole = matchingRoles.shift();
+ roles.push({name: roleName, displaylabel: matchingRole.text});
} else {
- CRM.loadForm(CRM.url('civicrm/admin/reltype', {action: 'add', reset: 1, label_a_b: roleName, label_b_a: roleName}))
+ CRM.loadForm(CRM.url('civicrm/admin/reltype', {action: 'add', reset: 1, label_a_b: roleName}))
.on('crmFormSuccess', function(e, data) {
var newType = _.values(data.relationshipType)[0];
- roles.push({name: newType[REL_TYPE_CNAME]});
- $scope.relationshipTypeOptions.push({id: newType[REL_TYPE_CNAME], text: newType.label_b_a});
+ roles.push({name: newType.label_b_a, displaylabel: newType.label_a_b});
+ // Assume that the case role should be A-B but add both directions as options.
+ $scope.relationshipTypeOptions.push({id: newType.label_a_b, text: newType.label_a_b});
+ if (newType.label_a_b != newType.label_b_a) {
+ $scope.relationshipTypeOptions.push({id: newType.label_b_a, text: newType.label_b_a});
+ }
$scope.$digest();
});
}
$scope.caseType.definition.activityAsgmtGrps = $scope.caseType.definition.activityAsgmtGrps.toString().split(",");
}
+ function dropDisplaylabel (v) {
+ delete v.displaylabel;
+ }
+
+ // strip out labels from $scope.caseType.definition.caseRoles
+ _.map($scope.caseType.definition.caseRoles, dropDisplaylabel);
+
var result = crmApi('CaseType', 'create', $scope.caseType, true);
result.then(function(data) {
if (data.is_error === 0 || data.is_error == '0') {
</thead>
<tbody>
<tr ng-repeat="relType in caseType.definition.caseRoles | orderBy:'name'" ng-class-even="'crm-entity even-row even'" ng-class-odd="'crm-entity odd-row odd'">
- <td>{{relType.name}}</td>
+ <!-- display label (client-perspective) -->
+ <td>{{relType.displaylabel}}</td>
<td><input type="checkbox" ng-model="relType.creator" ng-true-value="'1'" ng-false-value="'0'"></td>
<td><input type="radio" ng-model="relType.manager" value="1" ng-change="onManagerChange(relType)"></td>
<td>
CRM.resourceUrls = {
'civicrm': ''
};
- // CRM_Case_XMLProcessor::REL_TYPE_CNAME
- CRM.crmCaseType = {
- 'REL_TYPE_CNAME': 'label_b_a'
- };
module('crmCaseType');
module('crmJsonComparator');
inject(function(crmJsonComparator) {
}
]
},
+ relTypesForm: {
+ values: [
+ {
+ "key": "14_b_a",
+ "value": "Benefits Specialist"
+ },
+ {
+ "key": "14_a_b",
+ "value": "Benefits Specialist is"
+ },
+ {
+ "key": "9_b_a",
+ "value": "Case Coordinator"
+ },
+ {
+ "key": "9_a_b",
+ "value": "Case Coordinator is"
+ },
+ {
+ "key": "2_b_a",
+ "value": "Spouse of"
+ }
+ ]
+ },
caseType: {
"id": "1",
"name": "housing_support",
result.push({
label: relType.label_b_a,
- value: relType.id + '_b_a'
+ value: relType.id + '_a_b'
});
if (!isBidirectionalRelationship) {
result.push({
label: relType.label_a_b,
- value: relType.id + '_a_b'
+ value: relType.id + '_b_a'
});
}
}, []);
]);
//Check if manager is correctly retrieved from xml processor.
$xmlProcessor = new CRM_Case_XMLProcessor_Process();
- $this->assertEquals($relTypeID, $xmlProcessor->getCaseManagerRoleId('ForkableCaseType'));
+ $this->assertEquals($relTypeID . '_a_b', $xmlProcessor->getCaseManagerRoleId('ForkableCaseType'));
}
/**