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..82107f7bf5ba --- /dev/null +++ b/CRM/Case/ActionMapping.php @@ -0,0 +1,181 @@ +register(CRM_Case_ActionMapping::create([ + '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' => 'start_date', + 'entity_date_end' => 'end_date', + ])); + } + + /** + * @inheritdoc + */ + public function getRecipientListing($type) { + if ($type == 'case_roles') { + $result = civicrm_api3('RelationshipType', 'get', [ + 'sequential' => 1, + 'options' => ['limit' => 0, 'sort' => "label_b_a"], + ])['values']; + $cRoles = []; + foreach ($result as $each) { + $cRoles[$each['id']] = $each['label_b_a']; + } + return $cRoles; + } + return []; + } + + /** + * @inheritdoc + */ + public function getRecipientTypes() { + return ['case_roles' => 'Case Roles']; + } + + /** + * @inheritdoc + */ + public function getDateFields() { + return [ + 'start_date' => ts('Case Start Date'), + 'end_date' => ts('Case End Date'), + 'case_status_change_date' => ts('On Case Status Change'), + ]; + } + + /** + * @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("{$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 (#caseTypeId)") + ->param('caseTypeId', $selectedValues); + } + + if (!empty($selectedStatuses)) { + $query->where("c.status_id IN (#selectedStatuses)") + ->param('selectedStatuses', $selectedStatuses); + } + + 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"); + } + + 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"); + $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'; + $query['casContactTableAlias'] = 'ct'; + + // 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; + } +} 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'));