Activities can't be moved to a Case re-opened by the API
Overview
When the API sets a Case to an Open status, it does not clear the end date. When moving an Activity to a Case, the filter for the list of available cases requires the end date to be null. If a case has been closed and then reopened by the API (e.g. by filling out a webform which sets the case status), it will still have an end date, so it will not be available in this list.
The end date is not visible to the user, so there's no visual indication of why Cases reopened in this manner behave differently.
Reproduction steps (using the demo database)
- Choose or create a Contact with at least one Activity
- Create a Case for this Contact
- Set the Case status to Resolved using the UI or API
- Use the API explorer to set the status of that Case to Ongoing
- Go to the Contact's summary screen and click on Activities
- Choose any suitable Activity, click "File on Case"
- Search for the newly reopened Case and note that it does not appear in the list
Current behaviour
A Case can have an Open status and an end_date, meaning it is not possible to move Activities to that Case, and the reason isn't visible to the user.
- The API and webform-civicrm do not clear the end date when setting a case to an Opened status class
- The code which filters the list of available Cases when moving an Activity (example here) finds Open cases according to these criteria:
'case_id.is_deleted' => 0,
'case_id.status_id' => ['!=' => "Closed"],
'case_id.end_date' => ['IS NULL' => 1],
There are at least two other places which implement this logic (one in the same file, another here).
Expected behaviour
If a Case has an Open status, it should be possible to move Activities to that Case.
There are several places where this could be addressed, but I think the filter shown above should check the status class, and probably should not check the end_date at all.
If it does check the end_date:
- Either the API or webform-civicrm should clear the end date (if it's in the past) when setting a Case to an Opened status
- If this is done by webform-civicrm, should it also create the Changed Status activities which would have been created if the Case were re-opened through the normal UI?
- Should the filter include Cases with future end dates as well as null end dates?
Environment information
- CiviCRM: Discovered on 5.27.5, tested on 5.33.alpha1
- CMS: Drupal 7.74
- webform-civicrm: tested on 7.x-5.1 and 7.x-5.3
Comments
I can see reasons why the API might not want to clear the end date for a reopened Case, and how webform-civicrm is simply passing the submitted values along to the API. It's not clear which part of the system should be responsible, and I'm guessing most sites don't encounter this issue.
We considered using a CiviRule to do some extra processing when the Case status changes, but when attempting to configure this it fails with "Entity Case does not implement status condition". We can probably solve this by writing a custom CiviRule trigger (or maybe upgrading CiviRules), but it also seems like the core logic could be improved.
I've tested a patch locally which doesn't look at the end date when filtering the list of Cases in this context, and which looks for the Opened status classes by first fetching them like so:
$openStatuses = array_keys(CRM_Case_PseudoConstant::caseStatus('value', TRUE, "AND grouping = 'Opened'"));
Looking at the current code, I'm wondering whether this is checking the status class without needing to fetch the list first:
'case_id.status_id' => ['!=' => "Closed"],