All location tasks are being resolved at once

Hi everyone,

One question regarding tasks triggered from a location instead of patient. We have a form on location level (to anonymize the patient), that can be filled in by a CHW. When the form is filled in, it triggers a task which can later be finished by the CHW. If multiple Forms are filled in at location level, multiple tasks are triggered per form (let’s say three for simplicity). Having these three tasks, and assessing just one, will resolve all of the others. I assume this is because of the resolvedIf. Is there a way to construct the resolvedIf in a way that only one task is resolved? Ideally the one that was just clicked?

Currently I am working with this:

resolvedIf: function(contact, report, event, dueDate) {
      const startTime = Math.max(addDays(dueDate, -event.start).getTime(), report.reported_date);
      const endTime = addDays(dueDate, event.end + 1).getTime();
      let found;
      let forms = ['young_infant_afterlab'];
      contact.reports.forEach(function (c_report) {
        if (!forms.includes(c_report.form)) { return; }
        if (c_report._id === report._id) {
          found = true;
        }
      });
      return isFormArraySubmittedInWindow(
        contact.reports, ['young_infant_afterlab'], startTime, endTime
      ) ;
    }

_afterlab being the task and young_infant the form that triggers the task (for completeness). I was trying to work with the report ID but doesn’t work, I assume because it goes through all reports in the location and all tasks and it will find matches for each.

Any help would be appreciated.

Hopefully someone else has actually tried to do something similar and has a more complete answer, but I have a couple thoughts to share anyway.

First, your current implementation does not seem to be using found at all. It probably makes more sense to just drop the isFormArraySubmittedInWindow call and integrate that logic into your existing check. Something like:

resolvedIf: function(contact, report, event, dueDate) {
  const startTime = Math.max(addDays(dueDate, -event.start).getTime(), report.reported_date);
  const endTime = addDays(dueDate, event.end + 1).getTime();
  const forms = ['young_infant_afterlab'];
  const matchingReports = contact.reports
    .filter(c_report => forms.includes(c_report.form))
    .filter(c_report => c_report.reported_date >= startTime && c_report.reported_date <= endTime)
    .filter(c_report => c_report._id === report._id);
  return matchingReports.length > 0;
}

Secondly, though, I would not think you would actually want to match on the _id field since I don’t think that would ever be the same between two different reports. Instead, it seems like you might want to set a custom field (e.g. source_id) on the triggered young_infant_afterlab form (via the modifyContent functionality). I think you could set that to the _id of the source report and then here in the resolvedIf you would just check c_report.source_id === report._id)… Something like that.

3 Likes

Yes you are right, I had && found in the return but missed when copying it somehow.

Thanks a lot for your suggestion, in the 3rd filter statement you mean then c_report.source_id === report._id right?
I tried this, now they do not all get resolved, but none gets resolved. Which is weird, I do see the source_id in the task as stored in the database, and this corresponds to the _id of the young_infant, so should be giving matchingReports one result.
I also tried with getField(c_report, ‘source_id’) instead of c_report.source_id and also c_report.fields.inputs.source_id (as per DB entry) but no luck so far

in the 3rd filter statement you mean then c_report.source_id === report._id right?

Yes!

I tried this, now they do not all get resolved, but none gets resolved.

Hmm, this is strange! I was able to create a very simplified version of the behavior you are looking for with a test form called enketo_widgets that contains:

type name label::en appearance calculation
begin group inputs NO_LABEL field-list
string source NO_LABEL hidden
string source_id NO_LABEL hidden
begin group contact NO_LABEL
db:person _id Select Contact db-object
end group contact
end group inputs
calculate patient_id …/inputs/contact/_id
calculate patient_uuid …/inputs/contact/_id
string source_id Source ID

Then my task config looks like this:


  {
    name: 'enketo',
    icon: 'icon-mother-child',
    title: 'Enketo Task',
    appliesTo: 'reports',
    appliesToType: ['enketo_widgets'],
    appliesIf: function (contact, report) {
      return getField(report, 'source_id') === '';
    },
    resolvedIf: function(contact, report, event, dueDate) {
      const startTime = Math.max(addDays(dueDate, -event.start).getTime(), report.reported_date);
      const endTime = addDays(dueDate, event.end + 1).getTime();
      const forms = ['enketo_widgets'];
      const matchingReports = contact.reports
        .filter(c_report => forms.includes(c_report.form))
        .filter(c_report => c_report.reported_date >= startTime && c_report.reported_date <= endTime)
        .filter(c_report => getField(c_report, 'source_id') === report._id);
      return matchingReports.length > 0;
    },
    actions: [
      {
        form: 'enketo_widgets'
      }
    ],
    events: [
      {
        id: 'enketo-reminder',
        start: 4 * 7,
        end: 6 * 7,
        days: 1
      }
    ]
  },

If I submit an enketo_widget report and leave the source_id blank, then it triggers a new task. That task is resolved if I submit another enketo_widget report with a source_id value that matches the _id of the original report. A similar pattern should work for you!

One thing to watch out for (it tripped me up initially) is that both reports need to be associated with the same contact (via their patient_id/patient_uuid). The task generation/resolution logic only considers the reports for the specific contact in context.

Also, this is slightly unrelated, but you might have noticed that you did not actually need to do anything with modifyContent. I inadvertently discovered brand new emergent functionality in the CHT!!!

Humor aside, it does appear that this field is supplied by the system (with the exact value that I wanted) for reports that are created from a task. I have created a new docs issue to actually document this information…

Haha I was actually going to ask you why you don’t have a modifyContent, great to know!

After fixing some issues, it works as expected, thanks for this!

2 Likes