From 6a506634fddc8c1822835dc35f6b9cf07ac7710f Mon Sep 17 00:00:00 2001 From: Vinu Varshith Date: Thu, 19 Sep 2019 07:32:21 +0530 Subject: [PATCH 1/3] CATL-1114: Support Cases In Scheduled Reminders --- CRM/Admin/Form/ScheduleReminders.php | 1 + CRM/Case/ActionMapping.php | 138 ++++++++++++++++++ Civi/ActionSchedule/Mapping.php | 2 + Civi/Core/Container.php | 1 + .../CRM/Admin/Form/ScheduleReminders.tpl | 34 +++++ 5 files changed, 176 insertions(+) create mode 100644 CRM/Case/ActionMapping.php diff --git a/CRM/Admin/Form/ScheduleReminders.php b/CRM/Admin/Form/ScheduleReminders.php index b827be6910df..9b92765bd535 100644 --- a/CRM/Admin/Form/ScheduleReminders.php +++ b/CRM/Admin/Form/ScheduleReminders.php @@ -702,6 +702,7 @@ public function listTokens() { $tokens = array_merge(CRM_Core_SelectValues::eventTokens(), $tokens); $tokens = array_merge(CRM_Core_SelectValues::membershipTokens(), $tokens); $tokens = array_merge(CRM_Core_SelectValues::contributionTokens(), $tokens); + $tokens = array_merge(CRM_Core_SelectValues::caseTokens(), $tokens); return $tokens; } diff --git a/CRM/Case/ActionMapping.php b/CRM/Case/ActionMapping.php new file mode 100644 index 000000000000..009de99bf2ab --- /dev/null +++ b/CRM/Case/ActionMapping.php @@ -0,0 +1,138 @@ +register(CRM_Case_ActionMapping::create(array( + 'id' => CRM_Case_ActionMapping::CASE_MAPPING_ID, + 'entity' => 'civicrm_case', + 'entity_label' => ts('Case'), + 'entity_value' => 'case_type', + 'entity_value_label' => ts('Case Type'), + 'entity_status' => 'case_status', + 'entity_status_label' => ts('Case Status'), + 'entity_date_start' => 'case_start_date', + 'entity_date_end' => 'case_end_date', + ))); + } + + /** + * @inheritdoc + */ + public function getRecipientListing($type) { + if ($type == 'case_roles') { + $result = civicrm_api3('RelationshipType', 'get', array( + 'sequential' => 1, + 'options' => array('limit' => 0, 'sort' => "label_b_a"), + ))['values']; + $cRoles = array(); + foreach ($result as $each) { + $cRoles[$each['id']] = $each['label_b_a']; + } + return $cRoles; + } + return array(); + } + + /** + * @inheritdoc + */ + public function getRecipientTypes() { + return array('case_roles' => 'Case Roles'); + } + + /** + * @inheritdoc + */ + public function createQuery($schedule, $phase, $defaultParams) { + $selectedValues = (array) \CRM_Utils_Array::explodePadded($schedule->entity_value); + $selectedStatuses = (array) \CRM_Utils_Array::explodePadded($schedule->entity_status); + + $query = \CRM_Utils_SQL_Select::from("civicrm_case c")->param($defaultParams); + $query->join('r', "INNER JOIN civicrm_relationship r ON c.id = r.case_id"); + $query->join('cs', "INNER JOIN civicrm_contact ct ON r.contact_id_b = ct.id"); + $query->join('ce', "INNER JOIN civicrm_email ce ON ce.contact_id = ct.id"); + + if (!empty($selectedValues)) { + $query->where("c.case_type_id IN (#caseId)") + ->param('caseId', $selectedValues); + } + + if (!empty($selectedStatuses)) { + $query->where("c.status_id IN (#selectedStatuses)") + ->param('selectedStatuses', $selectedStatuses); + } + + if (!empty($caseRoles)) { + $query->where("r.relationship_type_id IN (#caseRoles)") + ->param('caseRoles', $caseRoles); + } + + if ($schedule->recipient_listing && $schedule->limit_to) { + switch ($schedule->recipient) { + case 'case_roles': + $caseRoles = (array) \CRM_Utils_Array::explodePadded($schedule->recipient_listing); + $query->where("r.relationship_type_id IN (#caseRoles)") + ->param('caseRoles', $caseRoles); + break; + } + } + + // $schedule->start_action_date is user-supplied data. validate. + if (!array_key_exists($schedule->start_action_date, $this->getDateFields())) { + throw new CRM_Core_Exception("Invalid date field"); + } + + $query['casDateField'] = $schedule->start_action_date; + $query['casAddlCheckFrom'] = 'civicrm_case c'; + $query['casContactIdField'] = 'ct.id'; + $query['casEntityIdField'] = 'r.case_id'; + $query['casContactTableAlias'] = 'ct'; + $query->where('r.is_active = 1 AND c.is_deleted = 0'); + + return $query; + } +} diff --git a/Civi/ActionSchedule/Mapping.php b/Civi/ActionSchedule/Mapping.php index d6a97eb1935c..95e3610e47ac 100644 --- a/Civi/ActionSchedule/Mapping.php +++ b/Civi/ActionSchedule/Mapping.php @@ -298,6 +298,8 @@ protected static function getValueLabelMap($name) { $valueLabelMap['auto_renew_options'] = \CRM_Core_OptionGroup::values('auto_renew_options'); $valueLabelMap['contact_date_reminder_options'] = \CRM_Core_OptionGroup::values('contact_date_reminder_options'); $valueLabelMap['civicrm_membership_type'] = \CRM_Member_PseudoConstant::membershipType(); + $valueLabelMap['case_type'] = \CRM_Case_PseudoConstant::caseType(); + $valueLabelMap['case_status'] = \CRM_Case_PseudoConstant::caseStatus(); $allCustomFields = \CRM_Core_BAO_CustomField::getFields(''); $dateFields = [ diff --git a/Civi/Core/Container.php b/Civi/Core/Container.php index 0dfebb73ed95..a2ba13c3e884 100644 --- a/Civi/Core/Container.php +++ b/Civi/Core/Container.php @@ -364,6 +364,7 @@ public function createEventDispatcher($container) { $dispatcher->addListener(\Civi\ActionSchedule\Events::MAPPINGS, ['CRM_Contribute_ActionMapping_ByType', 'onRegisterActionMappings']); $dispatcher->addListener(\Civi\ActionSchedule\Events::MAPPINGS, ['CRM_Event_ActionMapping', 'onRegisterActionMappings']); $dispatcher->addListener(\Civi\ActionSchedule\Events::MAPPINGS, ['CRM_Member_ActionMapping', 'onRegisterActionMappings']); + $dispatcher->addListener(\Civi\ActionSchedule\Events::MAPPINGS, ['CRM_Case_ActionMapping', 'onRegisterActionMappings']); if (\CRM_Utils_Constant::value('CIVICRM_FLEXMAILER_HACK_LISTENERS')) { \Civi\Core\Resolver::singleton()->call(CIVICRM_FLEXMAILER_HACK_LISTENERS, [$dispatcher]); diff --git a/templates/CRM/Admin/Form/ScheduleReminders.tpl b/templates/CRM/Admin/Form/ScheduleReminders.tpl index af38060d9523..98f7ca98b0bf 100644 --- a/templates/CRM/Admin/Form/ScheduleReminders.tpl +++ b/templates/CRM/Admin/Form/ScheduleReminders.tpl @@ -211,6 +211,40 @@ showHideLimitTo(); } + function caseRolesFilter() { + if(!$("#entity_1", $form).val()){ + return; + } + var caseType = $("#entity_1", $form).val(); + CRM.api3('CaseType', 'get', { + "id": {"IN":caseType} + }).done(function(result) { + if (!CRM._.isEmpty(result.values)) { + var values = []; + CRM._.each(result.values, function(v, i) { + CRM._.each(v.definition.caseRoles, function(v2, j) { + values.push(v2.name); + }); + }); + // filter options + $("#recipient_listing > option").each(function(i, val) { + var text = $(val).text(); + if ($.inArray(text, values) == -1) { + $(this).remove(); + } + }); + } + $("#recipientList", $form).show(); + }); + } + + $('#entity_1', $form).change(function () { + var recipient = $("#recipient", $form).val(); + if (recipient == 'case_roles') { + populateRecipient(); + } + }); + // CRM-14070 Hide limit-to when entity is activity function showHideLimitTo() { $('#limit_to', $form).toggle(!($('#entity_0', $form).val() == '1')); From cbd5945ec95f55c35a1ee01988403461d3c365cf Mon Sep 17 00:00:00 2001 From: Vinu Varshith Date: Fri, 20 Sep 2019 14:23:03 +0530 Subject: [PATCH 2/3] CATL-1114: Add Support For Case Status Change Option For Scheduled Reminders --- CRM/Case/ActionMapping.php | 50 +++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/CRM/Case/ActionMapping.php b/CRM/Case/ActionMapping.php index 009de99bf2ab..6b92fe42ae14 100644 --- a/CRM/Case/ActionMapping.php +++ b/CRM/Case/ActionMapping.php @@ -54,8 +54,8 @@ public static function onRegisterActionMappings(\Civi\ActionSchedule\Event\Mappi 'entity_value_label' => ts('Case Type'), 'entity_status' => 'case_status', 'entity_status_label' => ts('Case Status'), - 'entity_date_start' => 'case_start_date', - 'entity_date_end' => 'case_end_date', + 'entity_date_start' => 'start_date', + 'entity_date_end' => 'end_date', ))); } @@ -84,6 +84,17 @@ public function getRecipientTypes() { return array('case_roles' => 'Case Roles'); } + /** + * @inheritdoc + */ + public function getDateFields() { + return [ + 'start_date' => ts('Case Start Date'), + 'end_date' => ts('Case End Date'), + 'case_status' => ts('Case Status Change'), + ]; + } + /** * @inheritdoc */ @@ -126,7 +137,40 @@ public function createQuery($schedule, $phase, $defaultParams) { throw new CRM_Core_Exception("Invalid date field"); } - $query['casDateField'] = $schedule->start_action_date; + if ($schedule->start_action_date == 'case_status') { + // For this case, we use activity of type 'Change Case Status' and check if the case status has been changed + // from an indifferent status to the one configured in scheduled reminder. + $query->join('cac', "INNER JOIN civicrm_case_activity cac ON cac.case_id = c.id"); + $query->where("cac.id = (SELECT MAX(cac2.id) FROM civicrm_case_activity cac2 WHERE cac2.case_id = c.id)"); + + $query->join('act', "INNER JOIN civicrm_activity act ON act.id = cac.activity_id"); + $query->join('opt', "INNER JOIN civicrm_option_value opt ON opt.value = act.activity_type_id"); + $query->join('opg', "INNER JOIN civicrm_option_group opg ON opg.id = opt.option_group_id"); + $query->where("opt.name = 'Change Case Status'"); + $query->where("opg.name = 'activity_type'"); + + // If start condition is 'after' we check for completed activity + // and if 'before' we check for scheduled activity. + if ($schedule->start_action_condition == 'after') { + $activityStatus = 'Completed'; + } + else { + $activityStatus = 'Scheduled'; + } + + // Subquery to check for activity status. + $subQuery = \CRM_Utils_SQL_Select::from("civicrm_option_value opt2")->select('opt2.value'); + $subQuery->join('opg2', 'INNER JOIN civicrm_option_group opg2 ON opg2.id = opt2.option_group_id'); + $subQuery->where("opt2.name = @activityStatus")->param('activityStatus', $activityStatus); + $subQuery->where("opg2.name = 'activity_status'"); + $query->where("act.status_id = (" . $subQuery->toSQL() . ")"); + + $query['casDateField'] = 'act.activity_date_time'; + } + else { + $query['casDateField'] = 'c.' . $schedule->start_action_date; + } + $query['casAddlCheckFrom'] = 'civicrm_case c'; $query['casContactIdField'] = 'ct.id'; $query['casEntityIdField'] = 'r.case_id'; From 66c006746aa48ab029d2e1f5254dbc37550c9f6e Mon Sep 17 00:00:00 2001 From: Vinu Varshith Date: Tue, 24 Sep 2019 00:23:46 +0530 Subject: [PATCH 3/3] CATL-1114: Code Review Comments - Code Improvements --- CRM/Case/ActionMapping.php | 41 +++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/CRM/Case/ActionMapping.php b/CRM/Case/ActionMapping.php index 6b92fe42ae14..82107f7bf5ba 100644 --- a/CRM/Case/ActionMapping.php +++ b/CRM/Case/ActionMapping.php @@ -35,8 +35,6 @@ class CRM_Case_ActionMapping extends \Civi\ActionSchedule\Mapping { /** * The value for civicrm_action_schedule.mapping_id which identifies the * "Case" mapping. - * - * Note: This value is chosen to match legacy DB IDs. */ const CASE_MAPPING_ID = 99; @@ -46,7 +44,7 @@ class CRM_Case_ActionMapping extends \Civi\ActionSchedule\Mapping { * @param \Civi\ActionSchedule\Event\MappingRegisterEvent $registrations */ public static function onRegisterActionMappings(\Civi\ActionSchedule\Event\MappingRegisterEvent $registrations) { - $registrations->register(CRM_Case_ActionMapping::create(array( + $registrations->register(CRM_Case_ActionMapping::create([ 'id' => CRM_Case_ActionMapping::CASE_MAPPING_ID, 'entity' => 'civicrm_case', 'entity_label' => ts('Case'), @@ -56,7 +54,7 @@ public static function onRegisterActionMappings(\Civi\ActionSchedule\Event\Mappi 'entity_status_label' => ts('Case Status'), 'entity_date_start' => 'start_date', 'entity_date_end' => 'end_date', - ))); + ])); } /** @@ -64,24 +62,24 @@ public static function onRegisterActionMappings(\Civi\ActionSchedule\Event\Mappi */ public function getRecipientListing($type) { if ($type == 'case_roles') { - $result = civicrm_api3('RelationshipType', 'get', array( + $result = civicrm_api3('RelationshipType', 'get', [ 'sequential' => 1, - 'options' => array('limit' => 0, 'sort' => "label_b_a"), - ))['values']; - $cRoles = array(); + 'options' => ['limit' => 0, 'sort' => "label_b_a"], + ])['values']; + $cRoles = []; foreach ($result as $each) { $cRoles[$each['id']] = $each['label_b_a']; } return $cRoles; } - return array(); + return []; } /** * @inheritdoc */ public function getRecipientTypes() { - return array('case_roles' => 'Case Roles'); + return ['case_roles' => 'Case Roles']; } /** @@ -91,7 +89,7 @@ public function getDateFields() { return [ 'start_date' => ts('Case Start Date'), 'end_date' => ts('Case End Date'), - 'case_status' => ts('Case Status Change'), + 'case_status_change_date' => ts('On Case Status Change'), ]; } @@ -102,14 +100,14 @@ public function createQuery($schedule, $phase, $defaultParams) { $selectedValues = (array) \CRM_Utils_Array::explodePadded($schedule->entity_value); $selectedStatuses = (array) \CRM_Utils_Array::explodePadded($schedule->entity_status); - $query = \CRM_Utils_SQL_Select::from("civicrm_case c")->param($defaultParams); + $query = \CRM_Utils_SQL_Select::from("{$this->entity} c")->param($defaultParams); $query->join('r', "INNER JOIN civicrm_relationship r ON c.id = r.case_id"); $query->join('cs', "INNER JOIN civicrm_contact ct ON r.contact_id_b = ct.id"); $query->join('ce', "INNER JOIN civicrm_email ce ON ce.contact_id = ct.id"); if (!empty($selectedValues)) { - $query->where("c.case_type_id IN (#caseId)") - ->param('caseId', $selectedValues); + $query->where("c.case_type_id IN (#caseTypeId)") + ->param('caseTypeId', $selectedValues); } if (!empty($selectedStatuses)) { @@ -117,11 +115,6 @@ public function createQuery($schedule, $phase, $defaultParams) { ->param('selectedStatuses', $selectedStatuses); } - if (!empty($caseRoles)) { - $query->where("r.relationship_type_id IN (#caseRoles)") - ->param('caseRoles', $caseRoles); - } - if ($schedule->recipient_listing && $schedule->limit_to) { switch ($schedule->recipient) { case 'case_roles': @@ -137,7 +130,7 @@ public function createQuery($schedule, $phase, $defaultParams) { throw new CRM_Core_Exception("Invalid date field"); } - if ($schedule->start_action_date == 'case_status') { + if ($schedule->start_action_date == 'case_status_change_date') { // For this case, we use activity of type 'Change Case Status' and check if the case status has been changed // from an indifferent status to the one configured in scheduled reminder. $query->join('cac', "INNER JOIN civicrm_case_activity cac ON cac.case_id = c.id"); @@ -175,7 +168,13 @@ public function createQuery($schedule, $phase, $defaultParams) { $query['casContactIdField'] = 'ct.id'; $query['casEntityIdField'] = 'r.case_id'; $query['casContactTableAlias'] = 'ct'; - $query->where('r.is_active = 1 AND c.is_deleted = 0'); + + // Relationship is active. + $today = date('Ymd'); + $query->where("r.is_active = 1 AND ( r.end_date is NULL OR r.end_date >= {$today} ) )"); + + // Case is not deleted. + $query->where("c.is_deleted = 0"); return $query; }