Skip to content

Commit

Permalink
Support due date for contact-based tasks
Browse files Browse the repository at this point in the history
Closes #93
  • Loading branch information
alxndrsn committed Oct 23, 2018
1 parent dcc257c commit b8d2528
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 30 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## v1.18.4
* Support due date for contact-based tasks
* Add FIXME for unnamed test

## v1.18.3
* Check for uncommitted files before releasing

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "medic-conf",
"version": "1.18.3",
"version": "1.18.4",
"description": "Configure Medic Mobile deployments",
"main": "index.js",
"scripts": {
Expand Down
6 changes: 6 additions & 0 deletions src/nools/lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ function emitTasksForSchedule(c, schedule, r) {
} else {
dueDate = new Date(Utils.addDate(new Date(r.reported_date), event.days));
}
} else {
if(event.dueDate) {
dueDate = event.dueDate(c.contact, event);
} else {
dueDate = new Date(Utils.addDate(new Date(c.contact.reported_date), event.days));
}
}

if (!Utils.isTimely(dueDate, event)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"contact_summary": "",
"tasks": {
"rules": "define Target {_id: null,deleted: null,type: null,pass: null,date: null}define Contact {contact: null,reports: null}define Task {_id: null,deleted: null,doc: null,contact: null,icon: null,date: null,title: null,fields: null,resolved: null,priority: null,priorityLabel: null,reports: null,actions: null}rule GenerateEvents {when {c: Contact}then {var idx1,idx2,r,target,now=Utils.now(),targets=[{id:'active-pregnancies',appliesTo:'reports',date:'now',appliesIf:function(e,t){return'D'===t.form}},{id:'imm-children-registered-this-month',appliesTo:'contacts',date:function(e){return e.contact.reported_date},appliesToType:['person'],appliesIf:function(e){return e.age_in_months<=60}}],tasks=[];for(idx1=0;idx1<targets.length;++idx1)switch((target=targets[idx1]).appliesTo){case'contacts':c.contact&&-1!==target.appliesToType.indexOf(c.contact.type)&&emitContactBasedTargetFor(c,target);break;case'reports':for(idx2=0;idx2<c.reports.length;++idx2)r=c.reports[idx2],emitReportBasedTargetFor(c,r,target);break;default:throw new Error('unrecognised target type: '+target.appliesTo)}if(tasks)for(idx1=0;idx1<tasks.length;++idx1){var task=tasks[idx1];switch(task.appliesTo){case'reports':case'scheduled_tasks':for(idx2=0;idx2<c.reports.length;++idx2)r=c.reports[idx2],emitTasksForSchedule(c,task,r);break;case'contacts':c.contact&&-1!==task.appliesToType.indexOf(c.contact.type)&&emitTasksForSchedule(c,task);break;default:throw new Error('unrecognised task type: '+task.appliesTo)}}function emitTasksForSchedule(o,d,n){var e;if((!n||!d.appliesToType||-1!==d.appliesToType.indexOf(n.form))&&('scheduled_tasks'===d.appliesTo||!d.appliesIf||d.appliesIf(o,n)))if('scheduled_tasks'===d.appliesTo){if(n&&d.appliesIf){if(!n.scheduled_tasks)return;for(e=0;e<n.scheduled_tasks.length;e++)d.appliesIf(o,n,e)&&t(e)}}else t();function t(e){var t,a,s,i,r=null;for(t=0;t<d.events.length;t++)a=d.events[t],n&&(r=a.dueDate?a.dueDate(n,a,e):void 0!==e?new Date(Utils.addDate(new Date(n.scheduled_tasks[e].due),a.days)):new Date(Utils.addDate(new Date(n.reported_date),a.days))),Utils.isTimely(r,a)&&(i={_id:n?n._id+'-'+a.id:o.contact._id+'-'+d.id,deleted:!(!(o.contact&&o.contact.deleted||n)||!n.deleted),doc:o,contact:o.contact,icon:d.icon,date:r,title:d.title,resolved:!!n&&d.resolvedIf(o,n,a,r,e),actions:n?d.actions.map(c):[]},void 0!==e&&(i._id+='-'+e),'function'==typeof(s=d.priority)&&(s=s(o,n)),s&&(i.priority=s.level,i.priorityLabel=s.label),emit('task',new Task(i)))}function c(e){return{type:'report',form:e.form,label:e.label||'Follow up',content:{source:'task',source_id:n._id,contact:o.contact}}}}function emitContactBasedTargetFor(e,t){if(!t.appliesIf||t.appliesIf(e)){var a=!t.passesIf||!!t.passesIf(e),s=createTargetInstance(t.id,e.contact,a);s.date=t.date?t.date(e):now.getTime(),emitTargetInstance(s)}}function emitReportBasedTargetFor(e,t,a){var s,i;if(!a.appliesIf||a.appliesIf(e,t))if(a.emitCustom)a.emitCustom(e,t);else switch(i=!a.passesIf||!!a.passesIf(e,t),(s=createTargetInstance(a.id,t,i))._id=('report'===a.idType?t._id:e.contact._id)+'-'+a.id,emitTargetInstance(s),a.date){case'now':s.date=now.getTime()}}function createTargetInstance(e,t,a){return new Target({_id:t._id+'-'+e,deleted:!!t.deleted,type:e,pass:a,date:t.reported_date})}function emitTargetInstance(e){emit('target',e)}emit('_complete',{_id:!0});}}",
"rules": "define Target {_id: null,deleted: null,type: null,pass: null,date: null}define Contact {contact: null,reports: null}define Task {_id: null,deleted: null,doc: null,contact: null,icon: null,date: null,title: null,fields: null,resolved: null,priority: null,priorityLabel: null,reports: null,actions: null}rule GenerateEvents {when {c: Contact}then {var idx1,idx2,r,target,now=Utils.now(),targets=[{id:'active-pregnancies',appliesTo:'reports',date:'now',appliesIf:function(e,t){return'D'===t.form}},{id:'imm-children-registered-this-month',appliesTo:'contacts',date:function(e){return e.contact.reported_date},appliesToType:['person'],appliesIf:function(e){return e.age_in_months<=60}}],tasks=[];for(idx1=0;idx1<targets.length;++idx1)switch((target=targets[idx1]).appliesTo){case'contacts':c.contact&&-1!==target.appliesToType.indexOf(c.contact.type)&&emitContactBasedTargetFor(c,target);break;case'reports':for(idx2=0;idx2<c.reports.length;++idx2)r=c.reports[idx2],emitReportBasedTargetFor(c,r,target);break;default:throw new Error('unrecognised target type: '+target.appliesTo)}if(tasks)for(idx1=0;idx1<tasks.length;++idx1){var task=tasks[idx1];switch(task.appliesTo){case'reports':case'scheduled_tasks':for(idx2=0;idx2<c.reports.length;++idx2)r=c.reports[idx2],emitTasksForSchedule(c,task,r);break;case'contacts':c.contact&&-1!==task.appliesToType.indexOf(c.contact.type)&&emitTasksForSchedule(c,task);break;default:throw new Error('unrecognised task type: '+task.appliesTo)}}function emitTasksForSchedule(o,d,n){var e;if((!n||!d.appliesToType||-1!==d.appliesToType.indexOf(n.form))&&('scheduled_tasks'===d.appliesTo||!d.appliesIf||d.appliesIf(o,n)))if('scheduled_tasks'===d.appliesTo){if(n&&d.appliesIf){if(!n.scheduled_tasks)return;for(e=0;e<n.scheduled_tasks.length;e++)d.appliesIf(o,n,e)&&t(e)}}else t();function t(e){var t,a,s,i,r=null;for(t=0;t<d.events.length;t++)a=d.events[t],r=n?a.dueDate?a.dueDate(n,a,e):void 0!==e?new Date(Utils.addDate(new Date(n.scheduled_tasks[e].due),a.days)):new Date(Utils.addDate(new Date(n.reported_date),a.days)):a.dueDate?a.dueDate(o.contact,a):new Date(Utils.addDate(new Date(o.contact.reported_date),a.days)),Utils.isTimely(r,a)&&(i={_id:n?n._id+'-'+a.id:o.contact._id+'-'+d.id,deleted:!(!(o.contact&&o.contact.deleted||n)||!n.deleted),doc:o,contact:o.contact,icon:d.icon,date:r,title:d.title,resolved:!!n&&d.resolvedIf(o,n,a,r,e),actions:n?d.actions.map(c):[]},void 0!==e&&(i._id+='-'+e),'function'==typeof(s=d.priority)&&(s=s(o,n)),s&&(i.priority=s.level,i.priorityLabel=s.label),emit('task',new Task(i)))}function c(e){return{type:'report',form:e.form,label:e.label||'Follow up',content:{source:'task',source_id:n._id,contact:o.contact}}}}function emitContactBasedTargetFor(e,t){if(!t.appliesIf||t.appliesIf(e)){var a=!t.passesIf||!!t.passesIf(e),s=createTargetInstance(t.id,e.contact,a);s.date=t.date?t.date(e):now.getTime(),emitTargetInstance(s)}}function emitReportBasedTargetFor(e,t,a){var s,i;if(!a.appliesIf||a.appliesIf(e,t))if(a.emitCustom)a.emitCustom(e,t);else switch(i=!a.passesIf||!!a.passesIf(e,t),(s=createTargetInstance(a.id,t,i))._id=('report'===a.idType?t._id:e.contact._id)+'-'+a.id,emitTargetInstance(s),a.date){case'now':s.date=now.getTime()}}function createTargetInstance(e,t,a){return new Target({_id:t._id+'-'+e,deleted:!!t.deleted,type:e,pass:a,date:t.reported_date})}function emitTargetInstance(e){emit('target',e)}emit('_complete',{_id:!0});}}",
"schedules": {
"test": true
},
Expand Down
4 changes: 2 additions & 2 deletions test/fn/compile-app-settings.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function test(relativeProjectDir) {

.then(() => {
// then
assert.equal(fs.read(`${testDir}/../app_settings.expected.json`),
fs.read(`${testDir}/app_settings.json`));
assert.equal(fs.read(`${testDir}/app_settings.json`),
fs.read(`${testDir}/../app_settings.expected.json`));
});
}
60 changes: 34 additions & 26 deletions test/nools/lib.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const jsToString = require('../../src/lib/js-to-string');
const parseJs = require('../../src/lib/simple-js-parser');

const TEST_DATE = 1431143098575;
const TEST_DAY = new Date(1431122400000);

describe('nools lib', function() {
let idCounter;
Expand Down Expand Up @@ -291,7 +292,7 @@ describe('nools lib', function() {

// then
assert.deepEqual(emitted, [
{ _type:'task' },
{ _type:'task', date:TEST_DAY },
{ _type:'_complete', _id:true },
]);
});
Expand All @@ -312,7 +313,7 @@ describe('nools lib', function() {

// then
assert.deepEqual(emitted, [
{ _type:'task' },
{ _type:'task', date:TEST_DAY },
{ _type:'_complete', _id:true },
]);
});
Expand Down Expand Up @@ -350,7 +351,7 @@ describe('nools lib', function() {

// then
assert.deepEqual(emitted, [
{ _type:'task' },
{ _type:'task', date:TEST_DAY },
{ _type:'_complete', _id:true },
]);
});
Expand All @@ -368,9 +369,9 @@ describe('nools lib', function() {

// then
assert.deepEqual(emitted, [
{ _type:'task' },
{ _type:'task' },
{ _type:'task' },
{ _type:'task', date:TEST_DAY },
{ _type:'task', date:TEST_DAY },
{ _type:'task', date:TEST_DAY },
{ _type:'_complete', _id:true },
]);
});
Expand All @@ -388,12 +389,12 @@ describe('nools lib', function() {

// then
assert.deepEqual(emitted, [
{ _type:'task' },
{ _type:'task' },
{ _type:'task' },
{ _type:'task' },
{ _type:'task' },
{ _type:'task' },
{ _type:'task', date:TEST_DAY },
{ _type:'task', date:TEST_DAY },
{ _type:'task', date:TEST_DAY },
{ _type:'task', date:TEST_DAY },
{ _type:'task', date:TEST_DAY },
{ _type:'task', date:TEST_DAY },
{ _type:'_complete', _id:true },
]);
});
Expand All @@ -414,11 +415,11 @@ describe('nools lib', function() {

// then
assert.deepEqual(emitted, [
{ _type:'task' },
{ _type:'task' },
{ _type:'task' },
{ _type:'task' },
{ _type:'task' },
{ _type:'task', date:TEST_DAY },
{ _type:'task', date:TEST_DAY },
{ _type:'task', date:TEST_DAY },
{ _type:'task', date:TEST_DAY },
{ _type:'task', date:TEST_DAY },
{ _type:'_complete', _id:true },
]);
});
Expand Down Expand Up @@ -454,14 +455,21 @@ describe('nools lib', function() {
const tasks = ${jsToString(tasks)};
const emitted = [];
const Utils = {
addDate: function() {},
addDate: function(date, days) {
const d = new Date(date.getTime());
d.setDate(d.getDate() + days);
d.setHours(0, 0, 0, 0);
return d;
},
isTimely: function() { return true; },
};
class Target {};
class Task {};
function emit(type, task) {
task._type = type;
emitted.push(task);
const Task = function(props) {
this.date = props.date;
};
function emit(type, taskOrTarget) {
taskOrTarget._type = type;
emitted.push(taskOrTarget);
};
`,
export: [ 'emitted' ],
Expand Down Expand Up @@ -543,14 +551,14 @@ describe('nools lib', function() {

function aReport() {
++idCounter;
return { _id:`r-${idCounter}`, form:'F' };
return { _id:`r-${idCounter}`, form:'F', reported_date:TEST_DATE };
}

function aReportWithScheduledTasks(scheduledTaskCount) {
++idCounter;

const scheduled_tasks = [];
while(scheduledTaskCount--) scheduled_tasks.push({});
while(scheduledTaskCount--) scheduled_tasks.push({ due:TEST_DATE });

return { _id:`r-${idCounter}`, form:'F', scheduled_tasks };
}
Expand All @@ -561,7 +569,7 @@ describe('nools lib', function() {

function personWithReports(...reports) {
++idCounter;
return { contact:{ _id:`c-${idCounter}`, type:'person' }, reports };
return { contact:{ _id:`c-${idCounter}`, type:'person', reported_date:TEST_DATE }, reports };
}

function placeWithoutReports() {
Expand All @@ -570,6 +578,6 @@ describe('nools lib', function() {

function placeWithReports(...reports) {
++idCounter;
return { contact:{ _id:`c-${idCounter}`, type:'clinic' }, reports };
return { contact:{ _id:`c-${idCounter}`, type:'clinic', reported_date:TEST_DATE }, reports };
}
});

0 comments on commit b8d2528

Please sign in to comment.