← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 12939: Implement unit tests on ProgramInstance service methods

 

------------------------------------------------------------
revno: 12939
committer: Tran Chau <tran.hispvietnam@xxxxxxxxx>
branch nick: dhis2
timestamp: Thu 2013-11-14 15:17:57 +0700
message:
  Implement unit tests on ProgramInstance service methods
added:
  dhis-2/dhis-services/dhis-service-patient/src/test/java/org/hisp/dhis/program/ProgramInstanceServiceTest.java
  dhis-2/dhis-services/dhis-service-patient/src/test/java/org/hisp/dhis/program/ProgramInstanceStoreTest.java
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramInstance.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramInstanceService.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramInstanceStore.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/enrollment/AbstractEnrollmentService.java
  dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/DefaultProgramInstanceService.java
  dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/hibernate/HibernateProgramInstanceStore.java
  dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/DhisConvenienceTest.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/program/UpdateProgramAction.java


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramInstance.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramInstance.java	2013-11-07 06:13:35 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramInstance.java	2013-11-14 08:17:57 +0000
@@ -99,10 +99,11 @@
     {
     }
 
-    public ProgramInstance( Date enrollmentDate, Date endDate, Patient patient, Program program )
+    
+    public ProgramInstance( Date enrollmentDate, Date dateOfIncident, Patient patient, Program program )
     {
         this.enrollmentDate = enrollmentDate;
-        this.endDate = endDate;
+        this.dateOfIncident = dateOfIncident;
         this.patient = patient;
         this.program = program;
     }

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramInstanceService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramInstanceService.java	2013-11-04 03:49:17 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramInstanceService.java	2013-11-14 08:17:57 +0000
@@ -170,7 +170,7 @@
      * @return ProgramInstance list
      */
     Collection<ProgramInstance> getProgramInstances( Collection<Program> programs, Integer status );
-    
+
     /**
      * Retrieve program instances on a patient by a status
      * 
@@ -205,16 +205,6 @@
     Collection<ProgramInstance> getProgramInstances( Patient patient, Program program, Integer status );
 
     /**
-     * Retrieve program instances on an orgunit by a program
-     * 
-     * @param program Program
-     * @param organisationUnit Organisation Unit
-     * 
-     * @return ProgramInstance list
-     */
-    Collection<ProgramInstance> getProgramInstances( Program program, OrganisationUnit organisationUnit );
-
-    /**
      * Retrieve program instances with active status on an orgunit by a program
      * with result limited
      * 
@@ -250,11 +240,13 @@
      * @param organisationUnit Organisation Unit
      * @param startDate The start date for retrieving on enrollment-date
      * @param endDate The end date for retrieving on enrollment-date
+     * @param min
+     * @param max
      * 
      * @return ProgramInstance list
      */
     Collection<ProgramInstance> getProgramInstances( Program program, Collection<Integer> orgunitIds, Date startDate,
-        Date endDate, int min, int max );
+        Date endDate, Integer min, Integer max );
 
     /**
      * Get the number of program instances which are active status and
@@ -324,13 +316,7 @@
     int countProgramInstancesByStatus( Integer status, Program program, Collection<Integer> orgunitIds, Date startDate,
         Date endDate );
 
-    /**
-     * Remove a program instance
-     * 
-     * @param programInstance ProgramInstance
-     */
-    void removeProgramEnrollment( ProgramInstance programInstance );
-
+  
     /**
      * Retrieve scheduled list of patients registered
      * 

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramInstanceStore.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramInstanceStore.java	2013-11-04 03:49:17 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramInstanceStore.java	2013-11-14 08:17:57 +0000
@@ -52,7 +52,7 @@
      * 
      * @return ProgramInstance list
      */
-    Collection<ProgramInstance> get( Integer status );
+    Collection<ProgramInstance> getByStatus( Integer status );
 
     /**
      * Retrieve program instances on a program
@@ -152,16 +152,6 @@
     Collection<ProgramInstance> get( Patient patient, Program program, Integer status );
 
     /**
-     * Retrieve program instances on an orgunit by a program
-     * 
-     * @param program Program
-     * @param organisationUnit Organisation Unit
-     * 
-     * @return ProgramInstance list
-     */
-    Collection<ProgramInstance> get( Program program, OrganisationUnit organisationUnit );
-
-    /**
      * Retrieve program instances with active status on an orgunit by a program
      * with result limited
      * 
@@ -195,11 +185,13 @@
      * @param organisationUnit Organisation Unit
      * @param startDate The start date for retrieving on enrollment-date
      * @param endDate The end date for retrieving on enrollment-date
+     * @param min
+     * @param max
      * 
      * @return ProgramInstance list
      */
     Collection<ProgramInstance> get( Program program, Collection<Integer> orgunitIds, Date startDate, Date endDate,
-        int min, int max );
+        Integer min, Integer max );
 
     /**
      * Get the number of program instances of a program on an organisation unit
@@ -227,13 +219,6 @@
     int count( Program program, Collection<Integer> orgunitIds, Date startDate, Date endDate );
 
     /**
-     * Remove a program instance
-     * 
-     * @param programInstance ProgramInstance
-     */
-    void removeProgramEnrollment( ProgramInstance programInstance );
-
-    /**
      * Get the number of program instances of a program which have a certain
      * status and an orgunit ids list for a period
      * 

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/enrollment/AbstractEnrollmentService.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/enrollment/AbstractEnrollmentService.java	2013-11-12 08:56:05 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/enrollment/AbstractEnrollmentService.java	2013-11-14 08:17:57 +0000
@@ -192,7 +192,7 @@
     @Override
     public Enrollments getEnrollments( Program program, OrganisationUnit organisationUnit )
     {
-        return getEnrollments( programInstanceService.getProgramInstances( program, organisationUnit ) );
+        return getEnrollments( programInstanceService.getProgramInstances( program, organisationUnit, 0, null ) );
     }
 
     @Override

=== modified file 'dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/DefaultProgramInstanceService.java'
--- dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/DefaultProgramInstanceService.java	2013-11-04 03:49:17 +0000
+++ dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/DefaultProgramInstanceService.java	2013-11-14 08:17:57 +0000
@@ -171,7 +171,7 @@
 
     public Collection<ProgramInstance> getProgramInstances( Integer status )
     {
-        return programInstanceStore.get( status );
+        return programInstanceStore.getByStatus( status );
     }
 
     public void updateProgramInstance( ProgramInstance programInstance )
@@ -226,11 +226,6 @@
         return programInstanceStore.get( patient, program, status );
     }
 
-    public Collection<ProgramInstance> getProgramInstances( Program program, OrganisationUnit organisationUnit )
-    {
-        return programInstanceStore.get( program, organisationUnit );
-    }
-
     public Collection<ProgramInstance> getProgramInstances( Program program, OrganisationUnit organisationUnit,
         Integer min, Integer max )
     {
@@ -244,7 +239,7 @@
     }
 
     public Collection<ProgramInstance> getProgramInstances( Program program, Collection<Integer> orgunitIds,
-        Date startDate, Date endDate, int min, int max )
+        Date startDate, Date endDate, Integer min, Integer max )
     {
         return programInstanceStore.get( program, orgunitIds, startDate, endDate, min, max );
     }
@@ -547,12 +542,7 @@
     {
         return programInstanceStore.getByStatus( status, program, orgunitIds, startDate, endDate );
     }
-
-    public void removeProgramEnrollment( ProgramInstance programInstance )
-    {
-        programInstanceStore.removeProgramEnrollment( programInstance );
-    }
-
+    
     public Collection<SchedulingProgramObject> getScheduleMesssages()
     {
         Collection<SchedulingProgramObject> result = programInstanceStore

=== modified file 'dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/hibernate/HibernateProgramInstanceStore.java'
--- dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/hibernate/HibernateProgramInstanceStore.java	2013-11-04 03:49:17 +0000
+++ dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/hibernate/HibernateProgramInstanceStore.java	2013-11-14 08:17:57 +0000
@@ -58,7 +58,7 @@
     // -------------------------------------------------------------------------
 
     @SuppressWarnings( "unchecked" )
-    public Collection<ProgramInstance> get( Integer status )
+    public Collection<ProgramInstance> getByStatus( Integer status )
     {
         return getCriteria( Restrictions.eq( "status", status ) ).list();
     }
@@ -124,14 +124,6 @@
     }
 
     @SuppressWarnings( "unchecked" )
-    public Collection<ProgramInstance> get( Program program, OrganisationUnit organisationUnit )
-    {
-        return getCriteria( Restrictions.eq( "program", program ), Restrictions.isNull( "endDate" ) )
-            .createAlias( "patient", "patient" ).add( Restrictions.eq( "patient.organisationUnit", organisationUnit ) )
-            .list();
-    }
-
-    @SuppressWarnings( "unchecked" )
     public Collection<ProgramInstance> get( Program program, OrganisationUnit organisationUnit, Integer min, Integer max )
     {
         Criteria criteria = getCriteria( Restrictions.eq( "program", program ), Restrictions.isNull( "endDate" ) )
@@ -157,13 +149,18 @@
 
     @SuppressWarnings( "unchecked" )
     public Collection<ProgramInstance> get( Program program, Collection<Integer> orgunitIds, Date startDate,
-        Date endDate, int min, int max )
+        Date endDate, Integer min, Integer max )
     {
-        return getCriteria( Restrictions.eq( "program", program ), Restrictions.ge( "enrollmentDate", startDate ),
-            Restrictions.le( "enrollmentDate", endDate ) ).createAlias( "patient", "patient" )
-            .createAlias( "patient.organisationUnit", "organisationUnit" )
-            .add( Restrictions.in( "organisationUnit.id", orgunitIds ) ).addOrder( Order.asc( "patient.id" ) )
-            .setFirstResult( min ).setMaxResults( max ).list();
+        Criteria criteria = getCriteria( Restrictions.eq( "program", program ),
+            Restrictions.ge( "enrollmentDate", startDate ), Restrictions.le( "enrollmentDate", endDate ) )
+            .createAlias( "patient", "patient" ).createAlias( "patient.organisationUnit", "organisationUnit" )
+            .add( Restrictions.in( "organisationUnit.id", orgunitIds ) ).addOrder( Order.asc( "patient.id" ) );
+        if ( min != null && max != null )
+        {
+            criteria.setFirstResult( min ).setMaxResults( max );
+        }
+
+        return criteria.list();
     }
 
     public int count( Program program, OrganisationUnit organisationUnit )
@@ -189,10 +186,10 @@
         Date endDate )
     {
         Number rs = (Number) getCriteria( Restrictions.eq( "program", program ),
-            Restrictions.between( "endDate", startDate, endDate ) ).createAlias( "patient", "patient" )
+            Restrictions.between( "enrollmentDate", startDate, endDate ) ).createAlias( "patient", "patient" )
             .createAlias( "patient.organisationUnit", "organisationUnit" )
             .add( Restrictions.in( "organisationUnit.id", orgunitIds ) ).add( Restrictions.eq( "status", status ) )
-            .setProjection( Projections.projectionList().add( Projections.countDistinct( "id" ) ) ).uniqueResult();
+            .setProjection( Projections.rowCount() ).uniqueResult();
 
         return rs != null ? rs.intValue() : 0;
     }
@@ -201,23 +198,16 @@
     public Collection<ProgramInstance> getByStatus( Integer status, Program program, Collection<Integer> orgunitIds,
         Date startDate, Date endDate )
     {
-        return getCriteria( Restrictions.eq( "program", program ), Restrictions.between( "endDate", startDate, endDate ) )
-            .createAlias( "patient", "patient" ).createAlias( "patient.organisationUnit", "organisationUnit" )
+        return getCriteria( Restrictions.eq( "program", program ),
+            Restrictions.between( "enrollmentDate", startDate, endDate ) ).createAlias( "patient", "patient" )
+            .createAlias( "patient.organisationUnit", "organisationUnit" )
             .add( Restrictions.in( "organisationUnit.id", orgunitIds ) ).add( Restrictions.eq( "status", status ) )
             .list();
     }
 
-    public void removeProgramEnrollment( ProgramInstance programInstance )
-    {
-        String sql = "delete from programstageinstance where programinstanceid=" + programInstance.getId();
-        jdbcTemplate.execute( sql );
-
-        sql = "delete from programinstance where programinstanceid=" + programInstance.getId();
-        jdbcTemplate.execute( sql );
-    }
-
     public Collection<SchedulingProgramObject> getSendMesssageEvents( String dateToCompare )
     {
+
         String sql = " ( " + sendToPatientSql( dateToCompare ) + " ) ";
 
         sql += " UNION ( " + sendToHealthWorkerSql( dateToCompare ) + " ) ";
@@ -244,10 +234,10 @@
                 String organisationunitName = rs.getString( "orgunitName" );
                 String programName = rs.getString( "programName" );
                 String incidentDate = rs.getString( "dateofincident" ).split( " " )[0];// just
-                                                                                       // get
-                                                                                       // date,
-                                                                                       // remove
-                                                                                       // timestamp
+                                                                                        // get
+                                                                                        // date,
+                                                                                        // remove
+                                                                                        // timestamp
                 String daysSinceIncidentDate = rs.getString( "days_since_incident_date" );
                 String erollmentDate = rs.getString( "enrollmentdate" ).split( " " )[0];// just
                                                                                         // get
@@ -282,8 +272,8 @@
     {
         return "SELECT pi.programinstanceid, p.phonenumber, prm.templatemessage, "
             + "         p.name, org.name as orgunitName, " + "         pg.name as programName, pi.dateofincident , "
-            + "         pi.enrollmentdate,(DATE(now()) - DATE(pi.enrollmentdate) ) as days_since_erollment_date, "
-            + "         (DATE(now()) - DATE(pi.dateofincident) ) as days_since_incident_date "
+            + "         pi.enrollmentdate,(now() - pi.enrollmentdate ) as days_since_erollment_date, "
+            + "         (now() - pi.dateofincident) as days_since_incident_date "
             + "       FROM patient p INNER JOIN programinstance pi "
             + "              ON p.patientid=pi.patientid INNER JOIN program pg "
             + "              ON pg.programid=pi.programid INNER JOIN organisationunit org "
@@ -291,8 +281,8 @@
             + "              ON prm.programid = pi.programid " + "       WHERE pi.status= "
             + ProgramInstance.STATUS_ACTIVE + "         and p.phonenumber is not NULL and p.phonenumber != ''   "
             + "         and prm.templatemessage is not NULL and prm.templatemessage != ''   "
-            + "         and pg.type=1 and prm.daysallowedsendmessage is not null    "
-            + "         and ( DATE(now()) - DATE(pi." + dateToCompare + ") ) = prm.daysallowedsendmessage "
+            + "         and pg.type=1 and prm.daysallowedsendmessage is not null  " + "         and ( now() - pi."
+            + dateToCompare + " ) = prm.daysallowedsendmessage "
             + "         and prm.whenToSend is null and prm.dateToCompare='" + dateToCompare + "' and prm.sendto = "
             + PatientReminder.SEND_TO_PATIENT;
     }
@@ -300,8 +290,8 @@
     private String sendToHealthWorkerSql( String dateToCompare )
     {
         return "SELECT pi.programinstanceid, uif.phonenumber, prm.templatemessage, p.name, org.name as orgunitName, "
-            + "   pg.name as programName, pi.dateofincident, pi.enrollmentdate,(DATE(now()) - DATE(pi.enrollmentdate) ) as days_since_erollment_date, "
-            + "       (DATE(now()) - DATE(pi.dateofincident) ) as days_since_incident_date "
+            + "   pg.name as programName, pi.dateofincident, pi.enrollmentdate,(now() - pi.enrollmentdate ) as days_since_erollment_date, "
+            + "       (now() - pi.dateofincident ) as days_since_incident_date "
             + "    FROM patient p INNER JOIN programinstance pi "
             + "           ON p.patientid=pi.patientid INNER JOIN program pg "
             + "           ON pg.programid=pi.programid INNER JOIN organisationunit org "
@@ -311,16 +301,16 @@
             + "           ON us.userid=uif.userinfoid " + "    WHERE pi.status = " + ProgramInstance.STATUS_ACTIVE
             + "      and uif.phonenumber is not NULL and uif.phonenumber != '' "
             + "      and prm.templatemessage is not NULL and prm.templatemessage != '' "
-            + "      and pg.type=1 and prm.daysallowedsendmessage is not null " + "      and ( DATE(now()) - DATE( pi."
-            + dateToCompare + " ) ) = prm.daysallowedsendmessage " + " and prm.dateToCompare='" + dateToCompare
+            + "      and pg.type=1 and prm.daysallowedsendmessage is not null " + "      and (now() - pi."
+            + dateToCompare + " ) = prm.daysallowedsendmessage " + " and prm.dateToCompare='" + dateToCompare
             + "'     and prm.whenToSend is null and prm.sendto =  " + PatientReminder.SEND_TO_HEALTH_WORKER;
     }
 
     private String sendMessageToOrgunitRegisteredSql( String dateToCompare )
     {
         return "SELECT pi.programinstanceid, org.phonenumber, prm.templatemessage, p.name, org.name as orgunitName, "
-            + "   pg.name as programName, pi.dateofincident, pi.enrollmentdate,(DATE(now()) - DATE(pi.enrollmentdate) ) as days_since_erollment_date, "
-            + "       (DATE(now()) - DATE(pi.dateofincident) ) as days_since_incident_date "
+            + "   pg.name as programName, pi.dateofincident, pi.enrollmentdate,(now() - pi.enrollmentdate ) as days_since_erollment_date, "
+            + "       (now() - pi.dateofincident ) as days_since_incident_date "
             + "    FROM patient p INNER JOIN programinstance pi "
             + "           ON p.patientid=pi.patientid INNER JOIN program pg "
             + "           ON pg.programid=pi.programid INNER JOIN organisationunit org "
@@ -328,16 +318,16 @@
             + "           ON prm.programid = pi.programid " + "    WHERE pi.status = " + ProgramInstance.STATUS_ACTIVE
             + "      and org.phonenumber is not NULL and org.phonenumber != '' "
             + "      and prm.templatemessage is not NULL and prm.templatemessage != '' "
-            + "      and pg.type=1 and prm.daysallowedsendmessage is not null " + "      and ( DATE(now()) - DATE( pi."
-            + dateToCompare + " ) ) = prm.daysallowedsendmessage " + " and prm.dateToCompare='" + dateToCompare
+            + "      and pg.type=1 and prm.daysallowedsendmessage is not null " + "      and ( now() -  pi."
+            + dateToCompare + "  ) = prm.daysallowedsendmessage " + " and prm.dateToCompare='" + dateToCompare
             + "'     and prm.whenToSend is null and prm.sendto =  " + PatientReminder.SEND_TO_ORGUGNIT_REGISTERED;
     }
 
     private String sendMessageToUsersSql( String dateToCompare )
     {
         return "SELECT pi.programinstanceid, uif.phonenumber, prm.templatemessage, p.name, org.name as orgunitName, pg.name as programName, pi.dateofincident ,"
-            + "pi.enrollmentdate,(DATE(now()) - DATE(pi.enrollmentdate) ) as days_since_erollment_date, "
-            + "(DATE(now()) - DATE(pi.dateofincident) ) as days_since_incident_date "
+            + "pi.enrollmentdate,(now() - pi.enrollmentdate ) as days_since_erollment_date, "
+            + "(now() - pi.dateofincident ) as days_since_incident_date "
             + "FROM patient p INNER JOIN programinstance pi "
             + "    ON p.patientid=pi.patientid INNER JOIN program pg "
             + "    ON pg.programid=pi.programid INNER JOIN organisationunit org "
@@ -350,20 +340,19 @@
             + "         and uif.phonenumber is not NULL and uif.phonenumber != '' "
             + "         and prm.templatemessage is not NULL and prm.templatemessage != '' "
             + "         and pg.type=1 and prm.daysallowedsendmessage is not null "
-            + "         and ( DATE(now()) - DATE( "
+            + "         and ( now() - pi."
             + dateToCompare
-            + " ) ) = prm.daysallowedsendmessage "
+            + " )  = prm.daysallowedsendmessage "
             + "         and prm.dateToCompare='"
             + dateToCompare
-            + "'        and prm.sendto = "
-            + PatientReminder.SEND_TO_ALL_USERS_IN_ORGUGNIT_REGISTERED;
+            + "'        and prm.sendto = " + PatientReminder.SEND_TO_ALL_USERS_IN_ORGUGNIT_REGISTERED;
     }
 
     private String sendMessageToUserGroupsSql( String dateToCompare )
     {
         return "select pi.programinstanceid, uif.phonenumber,prm.templatemessage, p.name, org.name as orgunitName ,"
-            + " pg.name as programName, pi.dateofincident, pi.enrollmentdate, (DATE(now()) - DATE(pi.enrollmentdate) ) as days_since_erollment_date, "
-            + "(DATE(now()) - DATE(pi.dateofincident) ) as days_since_incident_date "
+            + " pg.name as programName, pi.dateofincident, pi.enrollmentdate, (now() - pi.enrollmentdate ) as days_since_erollment_date, "
+            + "(now() - pi.dateofincident ) as days_since_incident_date "
             + "  from patient p INNER JOIN programinstance pi " + "       ON p.patientid=pi.patientid "
             + "   INNER JOIN program pg " + "       ON pg.programid=pi.programid "
             + "   INNER JOIN organisationunit org " + "       ON org.organisationunitid = p.organisationunitid "
@@ -372,8 +361,9 @@
             + "   INNER JOIN userinfo uif " + "       ON uif.userinfoid = ugm.userid " + "  WHERE pi.status= "
             + ProgramInstance.STATUS_ACTIVE + "       and uif.phonenumber is not NULL and uif.phonenumber != '' "
             + "       and prm.templatemessage is not NULL and prm.templatemessage != '' "
-            + "       and pg.type=1 and prm.daysallowedsendmessage is not null " + "       and (  DATE(now()) - DATE("
-            + dateToCompare + ") ) = prm.daysallowedsendmessage " + "       and prm.whentosend is null "
+            + "       and pg.type=1 and prm.daysallowedsendmessage is not null " + "       and (  now() - pi."
+            + dateToCompare + " ) = prm.daysallowedsendmessage " + "       and prm.whentosend is null "
             + "       and prm.sendto = " + PatientReminder.SEND_TO_USER_GROUP;
     }
+
 }

=== added file 'dhis-2/dhis-services/dhis-service-patient/src/test/java/org/hisp/dhis/program/ProgramInstanceServiceTest.java'
--- dhis-2/dhis-services/dhis-service-patient/src/test/java/org/hisp/dhis/program/ProgramInstanceServiceTest.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-patient/src/test/java/org/hisp/dhis/program/ProgramInstanceServiceTest.java	2013-11-14 08:17:57 +0000
@@ -0,0 +1,612 @@
+/*
+ * Copyright (c) 2004-2013, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ *   list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * * Neither the name of the HISP project nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.hisp.dhis.program;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.hisp.dhis.DhisSpringTest;
+import org.hisp.dhis.mock.MockI18nFormat;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.organisationunit.OrganisationUnitService;
+import org.hisp.dhis.patient.Patient;
+import org.hisp.dhis.patient.PatientReminder;
+import org.hisp.dhis.patient.PatientService;
+import org.hisp.dhis.period.PeriodType;
+import org.hisp.dhis.sms.outbound.OutboundSms;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+/**
+ * @author Chau Thu Tran
+ * 
+ * @version $ ProgramInstanceServiceTest.java Nov 13, 2013 1:34:55 PM $
+ */
+public class ProgramInstanceServiceTest
+    extends DhisSpringTest
+{
+    @Autowired
+    private ProgramInstanceService programInstanceService;
+
+    @Autowired
+    private PatientService patientService;
+
+    @Autowired
+    private OrganisationUnitService organisationUnitService;
+
+    @Autowired
+    private ProgramService programService;
+
+    @Autowired
+    private ProgramStageService programStageService;
+
+    private Date incidenDate;
+
+    private Date enrollmentDate;
+
+    private Program programA;
+
+    private Program programB;
+
+    private Program programC;
+
+    private OrganisationUnit organisationUnitA;
+
+    private OrganisationUnit organisationUnitB;
+
+    private ProgramInstance programInstanceA;
+
+    private ProgramInstance programInstanceB;
+
+    private ProgramInstance programInstanceC;
+
+    private ProgramInstance programInstanceD;
+
+    private Patient patientA;
+
+    private Collection<Integer> orgunitIds;
+
+    private MockI18nFormat mockFormat;
+    
+    @Autowired
+    JdbcTemplate jdbcTemplate;
+    
+    @Override
+    public void setUpTest()
+    {
+        mockFormat = new MockI18nFormat();
+
+        organisationUnitA = createOrganisationUnit( 'A' );
+        int idA = organisationUnitService.addOrganisationUnit( organisationUnitA );
+
+        organisationUnitB = createOrganisationUnit( 'B' );
+        int idB = organisationUnitService.addOrganisationUnit( organisationUnitB );
+
+        orgunitIds = new HashSet<Integer>();
+        orgunitIds.add( idA );
+        orgunitIds.add( idB );
+
+        programA = createProgram( 'A', new HashSet<ProgramStage>(), organisationUnitA );
+        
+        PatientReminder patientReminderA = new PatientReminder( "A", 0, "Test program message template "
+            + PatientReminder.TEMPLATE_MESSSAGE_PATIENT_NAME, PatientReminder.ENROLLEMENT_DATE_TO_COMPARE,
+            PatientReminder.SEND_TO_PATIENT, null, PatientReminder.MESSAGE_TYPE_BOTH );
+        
+        PatientReminder patientReminderB = new PatientReminder( "B", 0, "Test program message template "
+            + PatientReminder.TEMPLATE_MESSSAGE_PATIENT_NAME, PatientReminder.ENROLLEMENT_DATE_TO_COMPARE,
+            PatientReminder.SEND_TO_PATIENT, PatientReminder.SEND_WHEN_TO_C0MPLETED_EVENT,
+            PatientReminder.MESSAGE_TYPE_BOTH );
+        
+        Set<PatientReminder> patientReminders = new HashSet<PatientReminder>();
+        patientReminders.add( patientReminderA );
+        patientReminders.add( patientReminderB );
+        programA.setPatientReminders( patientReminders );
+        
+        programService.addProgram( programA ); 
+        
+        
+        ProgramStage stageA = new ProgramStage( "StageA", programA );
+        programStageService.saveProgramStage( stageA );
+
+        ProgramStage stageB = new ProgramStage( "StageB", programA );
+        programStageService.saveProgramStage( stageB );
+
+        Set<ProgramStage> programStages = new HashSet<ProgramStage>();
+        programStages.add( stageA );
+        programStages.add( stageB );
+        programA.setProgramStages( programStages );
+        programService.updateProgram( programA );
+
+        programB = createProgram( 'B', new HashSet<ProgramStage>(), organisationUnitA );
+        programService.addProgram( programB );
+
+        programC = createProgram( 'C', new HashSet<ProgramStage>(), organisationUnitA );
+        programService.addProgram( programC );
+
+        patientA = createPatient( 'A', organisationUnitA );
+        patientService.savePatient( patientA );
+
+        Patient patientB = createPatient( 'B', organisationUnitB );
+        patientService.savePatient( patientB );
+
+        Calendar calIncident = Calendar.getInstance();
+        PeriodType.clearTimeOfDay( calIncident );
+        calIncident.add( Calendar.DATE, -70 );
+        incidenDate = calIncident.getTime();
+
+        Calendar calEnrollment = Calendar.getInstance();
+        PeriodType.clearTimeOfDay( calEnrollment );
+        enrollmentDate = calEnrollment.getTime();
+
+        programInstanceA = new ProgramInstance( enrollmentDate, incidenDate, patientA, programA );
+        programInstanceA.setUid( "UID-A" );
+
+        programInstanceB = new ProgramInstance( enrollmentDate, incidenDate, patientA, programB );
+        programInstanceB.setUid( "UID-B" );
+        programInstanceB.setStatus( ProgramInstance.STATUS_CANCELLED );
+
+        programInstanceC = new ProgramInstance( enrollmentDate, incidenDate, patientA, programC );
+        programInstanceC.setUid( "UID-C" );
+        programInstanceC.setStatus( ProgramInstance.STATUS_COMPLETED );
+
+        programInstanceD = new ProgramInstance( enrollmentDate, incidenDate, patientB, programA );
+        programInstanceD.setUid( "UID-D" );
+    }
+
+    @Test
+    public void testAddProgramInstance()
+    {
+        int idA = programInstanceService.addProgramInstance( programInstanceA );
+        int idB = programInstanceService.addProgramInstance( programInstanceB );
+
+        assertNotNull( programInstanceService.getProgramInstance( idA ) );
+        assertNotNull( programInstanceService.getProgramInstance( idB ) );
+    }
+
+    @Test
+    public void testDeleteProgramInstance()
+    {
+        int idA = programInstanceService.addProgramInstance( programInstanceA );
+        int idB = programInstanceService.addProgramInstance( programInstanceB );
+
+        assertNotNull( programInstanceService.getProgramInstance( idA ) );
+        assertNotNull( programInstanceService.getProgramInstance( idB ) );
+
+        programInstanceService.deleteProgramInstance( programInstanceA );
+
+        assertNull( programInstanceService.getProgramInstance( idA ) );
+        assertNotNull( programInstanceService.getProgramInstance( idB ) );
+
+        programInstanceService.deleteProgramInstance( programInstanceB );
+
+        assertNull( programInstanceService.getProgramInstance( idA ) );
+        assertNull( programInstanceService.getProgramInstance( idB ) );
+
+    }
+
+    @Test
+    public void testUpdateProgramInstance()
+    {
+        int idA = programInstanceService.addProgramInstance( programInstanceA );
+
+        assertNotNull( programInstanceService.getProgramInstance( idA ) );
+
+        programInstanceA.setDateOfIncident( enrollmentDate );
+        programInstanceService.updateProgramInstance( programInstanceA );
+
+        assertEquals( enrollmentDate, programInstanceService.getProgramInstance( idA ).getDateOfIncident() );
+    }
+
+    @Test
+    public void testGetProgramInstanceById()
+    {
+        int idA = programInstanceService.addProgramInstance( programInstanceA );
+        int idB = programInstanceService.addProgramInstance( programInstanceB );
+
+        assertEquals( programInstanceA, programInstanceService.getProgramInstance( idA ) );
+        assertEquals( programInstanceB, programInstanceService.getProgramInstance( idB ) );
+    }
+
+    @Test
+    public void testGetProgramInstanceByUid()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceB );
+
+        assertEquals( "UID-A", programInstanceService.getProgramInstance( "UID-A" ).getUid() );
+        assertEquals( "UID-B", programInstanceService.getProgramInstance( "UID-B" ).getUid() );
+    }
+
+    @Test
+    public void testGetAllProgramInstances()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceB );
+
+        assertTrue( equals( programInstanceService.getAllProgramInstances(), programInstanceA, programInstanceB ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByStatus()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceB );
+        programInstanceService.addProgramInstance( programInstanceC );
+        programInstanceService.addProgramInstance( programInstanceD );
+
+        Collection<ProgramInstance> programInstances = programInstanceService
+            .getProgramInstances( ProgramInstance.STATUS_ACTIVE );
+        assertEquals( 2, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+        assertTrue( programInstances.contains( programInstanceD ) );
+
+        programInstances = programInstanceService.getProgramInstances( ProgramInstance.STATUS_CANCELLED );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceB ) );
+
+        programInstances = programInstanceService.getProgramInstances( ProgramInstance.STATUS_COMPLETED );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceC ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByProgram()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceB );
+        programInstanceService.addProgramInstance( programInstanceD );
+
+        Collection<ProgramInstance> programInstances = programInstanceService.getProgramInstances( programA );
+        assertEquals( 2, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+        assertTrue( programInstances.contains( programInstanceD ) );
+
+        programInstances = programInstanceService.getProgramInstances( programB );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceB ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByProgramList()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceB );
+        programInstanceService.addProgramInstance( programInstanceC );
+        programInstanceService.addProgramInstance( programInstanceD );
+
+        Collection<Program> programs = new HashSet<Program>();
+        programs.add( programA );
+        programs.add( programB );
+
+        Collection<ProgramInstance> programInstances = programInstanceService.getProgramInstances( programs );
+        assertEquals( 3, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+        assertTrue( programInstances.contains( programInstanceB ) );
+        assertTrue( programInstances.contains( programInstanceD ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByOuProgramList()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceB );
+        programInstanceService.addProgramInstance( programInstanceC );
+        programInstanceService.addProgramInstance( programInstanceD );
+
+        Collection<Program> programs = new HashSet<Program>();
+        programs.add( programA );
+        programs.add( programB );
+
+        Collection<ProgramInstance> programInstances = programInstanceService.getProgramInstances( programs,
+            organisationUnitA );
+        assertEquals( 2, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+        assertTrue( programInstances.contains( programInstanceB ) );
+
+        programInstances = programInstanceService.getProgramInstances( programs, organisationUnitB );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceD ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByOuProgramListStatus()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceB );
+        programInstanceService.addProgramInstance( programInstanceC );
+
+        Collection<Program> programs = new HashSet<Program>();
+        programs.add( programA );
+        programs.add( programB );
+        programs.add( programC );
+
+        Collection<ProgramInstance> programInstances = programInstanceService.getProgramInstances( programs,
+            organisationUnitA, ProgramInstance.STATUS_ACTIVE );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+
+        programInstances = programInstanceService.getProgramInstances( programs, organisationUnitA,
+            ProgramInstance.STATUS_COMPLETED );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceC ) );
+
+    }
+
+    @Test
+    public void testGetProgramInstancesByProgramStatus()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceB );
+        programInstanceService.addProgramInstance( programInstanceC );
+        programInstanceService.addProgramInstance( programInstanceD );
+
+        Collection<ProgramInstance> programInstances = programInstanceService.getProgramInstances( programA,
+            ProgramInstance.STATUS_ACTIVE );
+        assertEquals( 2, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+        assertTrue( programInstances.contains( programInstanceD ) );
+
+        programInstances = programInstanceService.getProgramInstances( programB, ProgramInstance.STATUS_CANCELLED );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceB ) );
+
+        programInstances = programInstanceService.getProgramInstances( programC, ProgramInstance.STATUS_COMPLETED );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceC ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByProgramListStatus()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceB );
+        programInstanceService.addProgramInstance( programInstanceC );
+        programInstanceService.addProgramInstance( programInstanceD );
+
+        Collection<Program> programs = new HashSet<Program>();
+        programs.add( programA );
+        programs.add( programB );
+
+        Collection<ProgramInstance> programInstances = programInstanceService.getProgramInstances( programs,
+            ProgramInstance.STATUS_ACTIVE );
+        assertEquals( 2, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+        assertTrue( programInstances.contains( programInstanceD ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByPatientStatus()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceD );
+
+        Collection<Program> programs = new HashSet<Program>();
+        programs.add( programA );
+        programs.add( programB );
+
+        Collection<ProgramInstance> programInstances = programInstanceService.getProgramInstances( patientA,
+            ProgramInstance.STATUS_ACTIVE );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByPatientProgram()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceD );
+
+        ProgramInstance programInstance = programInstanceService.enrollPatient( patientA, programA, enrollmentDate,
+            incidenDate, organisationUnitA, null );
+        programInstance.setStatus( ProgramInstance.STATUS_COMPLETED );
+        programInstanceService.updateProgramInstance( programInstance );
+
+        Collection<ProgramInstance> programInstances = programInstanceService.getProgramInstances( patientA, programA );
+        assertEquals( 2, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+        assertTrue( programInstances.contains( programInstance ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByPatientProgramStatus()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+
+        ProgramInstance programInstance1 = programInstanceService.enrollPatient( patientA, programA, enrollmentDate,
+            incidenDate, organisationUnitA, null );
+        programInstance1.setStatus( ProgramInstance.STATUS_COMPLETED );
+        programInstanceService.updateProgramInstance( programInstance1 );
+
+        ProgramInstance programInstance2 = programInstanceService.enrollPatient( patientA, programA, enrollmentDate,
+            incidenDate, organisationUnitA, null );
+        programInstance2.setStatus( ProgramInstance.STATUS_COMPLETED );
+        programInstanceService.updateProgramInstance( programInstance2 );
+
+        Collection<ProgramInstance> programInstances = programInstanceService.getProgramInstances( patientA, programA,
+            ProgramInstance.STATUS_COMPLETED );
+        assertEquals( 2, programInstances.size() );
+        assertTrue( programInstances.contains( programInstance1 ) );
+        assertTrue( programInstances.contains( programInstance2 ) );
+
+        programInstances = programInstanceService.getProgramInstances( patientA, programA,
+            ProgramInstance.STATUS_ACTIVE );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByOuProgram()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceC );
+        programInstanceService.addProgramInstance( programInstanceD );
+
+        Collection<ProgramInstance> programInstances = programInstanceService.getProgramInstances( programA,
+            organisationUnitA, 0, 10 );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesbyProgramOuPeriod()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceD );
+
+        Collection<ProgramInstance> programInstances = programInstanceService.getProgramInstances( programA,
+            organisationUnitA, incidenDate, enrollmentDate );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByOuListProgramPeriod()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceB );
+        programInstanceService.addProgramInstance( programInstanceD );
+
+        Collection<ProgramInstance> programInstances = programInstanceService.getProgramInstances( programA,
+            orgunitIds, incidenDate, enrollmentDate, null, null );
+        assertEquals( 2, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+        assertTrue( programInstances.contains( programInstanceD ) );
+    }
+
+    @Test
+    public void testCountProgramInstancesByOuListProgramPeriod()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceB );
+        programInstanceService.addProgramInstance( programInstanceD );
+
+        int count = programInstanceService.countProgramInstances( programA, orgunitIds, incidenDate, enrollmentDate );
+        assertEquals( 2, count );
+    }
+
+    @Test
+    public void testGetProgramInstancesByOuListProgramStatusPeriod()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceB );
+        programInstanceService.addProgramInstance( programInstanceD );
+
+        Collection<ProgramInstance> programInstances = programInstanceService.getProgramInstancesByStatus(
+            ProgramInstance.STATUS_ACTIVE, programA, orgunitIds, incidenDate, enrollmentDate );
+        assertEquals( 2, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+        assertTrue( programInstances.contains( programInstanceD ) );
+    }
+
+    @Test
+    public void testCountProgramInstancesByStatus()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceB );
+        programInstanceService.addProgramInstance( programInstanceD );
+
+        int count = programInstanceService.countProgramInstancesByStatus( ProgramInstance.STATUS_ACTIVE, programA,
+            orgunitIds, incidenDate, enrollmentDate );
+        assertEquals( 2, count );
+    }
+
+    @Test
+    public void testSendMessages()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        Collection<OutboundSms> outboundSmsList = programInstanceService.sendMessages( programInstanceA,
+            PatientReminder.SEND_WHEN_TO_C0MPLETED_EVENT, mockFormat );
+        assertEquals( 1, outboundSmsList.size() );
+        assertEquals( "Test program message template NameA", outboundSmsList.iterator().next().getMessage() );
+    }
+
+    @Test
+    public void testSendMessageConversations()
+    {
+        programInstanceService.addProgramInstance( programInstanceB );
+
+        Collection<OutboundSms> outboundSmsList = programInstanceService.sendMessages( programInstanceA,
+            PatientReminder.SEND_WHEN_TO_C0MPLETED_EVENT, mockFormat );
+        assertEquals( 1, outboundSmsList.size() );
+        assertEquals( "Test program message template NameA", outboundSmsList.iterator().next().getMessage() );
+    }
+
+    @Test
+    public void testEnrollPatient()
+    {
+        ProgramInstance programInstance = programInstanceService.enrollPatient( patientA, programB, enrollmentDate,
+            incidenDate, organisationUnitA, mockFormat );
+
+        assertNotNull( programInstanceService.getProgramInstance( programInstance.getId() ) );
+    }
+
+    @Test
+    public void testCanAutoCompleteProgramInstanceStatus()
+    {
+        programInstanceService.addProgramInstance( programInstanceA );
+        programInstanceService.addProgramInstance( programInstanceD );
+
+        assertTrue( programInstanceService.canAutoCompleteProgramInstanceStatus( programInstanceA ) );
+        assertTrue( programInstanceService.canAutoCompleteProgramInstanceStatus( programInstanceD ) );
+    }
+
+    @Test
+    public void testCompleteProgramInstanceStatus()
+    {
+        int idA = programInstanceService.addProgramInstance( programInstanceA );
+        int idD = programInstanceService.addProgramInstance( programInstanceD );
+
+        programInstanceService.completeProgramInstanceStatus( programInstanceA, mockFormat );
+        programInstanceService.completeProgramInstanceStatus( programInstanceD, mockFormat );
+
+        assertEquals( ProgramInstance.STATUS_COMPLETED, programInstanceService.getProgramInstance( idA ).getStatus() );
+        assertEquals( ProgramInstance.STATUS_COMPLETED, programInstanceService.getProgramInstance( idD ).getStatus() );
+    }
+
+    @Test
+    public void testCancelProgramInstanceStatus()
+    {
+        int idA = programInstanceService.addProgramInstance( programInstanceA );
+        int idD = programInstanceService.addProgramInstance( programInstanceD );
+
+        programInstanceService.cancelProgramInstanceStatus( programInstanceA );
+        programInstanceService.cancelProgramInstanceStatus( programInstanceD );
+
+        assertEquals( ProgramInstance.STATUS_CANCELLED, programInstanceService.getProgramInstance( idA ).getStatus() );
+        assertEquals( ProgramInstance.STATUS_CANCELLED, programInstanceService.getProgramInstance( idD ).getStatus() );
+    }
+}

=== added file 'dhis-2/dhis-services/dhis-service-patient/src/test/java/org/hisp/dhis/program/ProgramInstanceStoreTest.java'
--- dhis-2/dhis-services/dhis-service-patient/src/test/java/org/hisp/dhis/program/ProgramInstanceStoreTest.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-patient/src/test/java/org/hisp/dhis/program/ProgramInstanceStoreTest.java	2013-11-14 08:17:57 +0000
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2004-2013, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ *   list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * * Neither the name of the HISP project nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.hisp.dhis.program;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.hisp.dhis.DhisSpringTest;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.organisationunit.OrganisationUnitService;
+import org.hisp.dhis.patient.Patient;
+import org.hisp.dhis.patient.PatientReminder;
+import org.hisp.dhis.patient.PatientService;
+import org.hisp.dhis.period.PeriodType;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+/**
+ * @author Chau Thu Tran
+ * 
+ * @version $ ProgramInstanceServiceTest.java Nov 13, 2013 1:34:55 PM $
+ */
+public class ProgramInstanceStoreTest
+    extends DhisSpringTest
+{
+    @Autowired
+    private ProgramInstanceStore programInstanceStore;
+
+    @Autowired
+    private PatientService patientService;
+
+    @Autowired
+    private OrganisationUnitService organisationUnitService;
+
+    @Autowired
+    private ProgramService programService;
+
+    @Autowired
+    private ProgramStageService programStageService;
+
+    private Date incidenDate;
+
+    private Date enrollmentDate;
+
+    private Program programA;
+
+    private Program programB;
+
+    private Program programC;
+
+    private OrganisationUnit organisationUnitA;
+
+    private OrganisationUnit organisationUnitB;
+
+    private ProgramInstance programInstanceA;
+
+    private ProgramInstance programInstanceB;
+
+    private ProgramInstance programInstanceC;
+
+    private ProgramInstance programInstanceD;
+
+    private Patient patientA;
+
+    private Collection<Integer> orgunitIds;
+
+    @Autowired
+    JdbcTemplate jdbcTemplate;
+
+    @Override
+    public void setUpTest()
+    {
+        organisationUnitA = createOrganisationUnit( 'A' );
+        int idA = organisationUnitService.addOrganisationUnit( organisationUnitA );
+
+        organisationUnitB = createOrganisationUnit( 'B' );
+        int idB = organisationUnitService.addOrganisationUnit( organisationUnitB );
+
+        orgunitIds = new HashSet<Integer>();
+        orgunitIds.add( idA );
+        orgunitIds.add( idB );
+
+        programA = createProgram( 'A', new HashSet<ProgramStage>(), organisationUnitA );
+
+        PatientReminder patientReminderA = new PatientReminder( "A", 0, "Test program message template "
+            + PatientReminder.TEMPLATE_MESSSAGE_PATIENT_NAME, PatientReminder.ENROLLEMENT_DATE_TO_COMPARE,
+            PatientReminder.SEND_TO_PATIENT, null, PatientReminder.MESSAGE_TYPE_BOTH );
+
+        PatientReminder patientReminderB = new PatientReminder( "B", 0, "Test program message template "
+            + PatientReminder.TEMPLATE_MESSSAGE_PATIENT_NAME, PatientReminder.ENROLLEMENT_DATE_TO_COMPARE,
+            PatientReminder.SEND_TO_PATIENT, PatientReminder.SEND_WHEN_TO_C0MPLETED_EVENT,
+            PatientReminder.MESSAGE_TYPE_BOTH );
+
+        Set<PatientReminder> patientReminders = new HashSet<PatientReminder>();
+        patientReminders.add( patientReminderA );
+        patientReminders.add( patientReminderB );
+        programA.setPatientReminders( patientReminders );
+
+        programService.addProgram( programA );
+
+        ProgramStage stageA = new ProgramStage( "StageA", programA );
+        programStageService.saveProgramStage( stageA );
+
+        ProgramStage stageB = new ProgramStage( "StageB", programA );
+        programStageService.saveProgramStage( stageB );
+
+        Set<ProgramStage> programStages = new HashSet<ProgramStage>();
+        programStages.add( stageA );
+        programStages.add( stageB );
+        programA.setProgramStages( programStages );
+        programService.updateProgram( programA );
+
+        programB = createProgram( 'B', new HashSet<ProgramStage>(), organisationUnitA );
+        programService.addProgram( programB );
+
+        programC = createProgram( 'C', new HashSet<ProgramStage>(), organisationUnitA );
+        programService.addProgram( programC );
+
+        patientA = createPatient( 'A', organisationUnitA );
+        patientService.savePatient( patientA );
+
+        Patient patientB = createPatient( 'B', organisationUnitB );
+        patientService.savePatient( patientB );
+
+        Calendar calIncident = Calendar.getInstance();
+        PeriodType.clearTimeOfDay( calIncident );
+        calIncident.add( Calendar.DATE, -70 );
+        incidenDate = calIncident.getTime();
+
+        Calendar calEnrollment = Calendar.getInstance();
+        PeriodType.clearTimeOfDay( calEnrollment );
+        enrollmentDate = calEnrollment.getTime();
+
+        programInstanceA = new ProgramInstance( enrollmentDate, incidenDate, patientA, programA );
+        programInstanceA.setUid( "UID-A" );
+
+        programInstanceB = new ProgramInstance( enrollmentDate, incidenDate, patientA, programB );
+        programInstanceB.setUid( "UID-B" );
+        programInstanceB.setStatus( ProgramInstance.STATUS_CANCELLED );
+
+        programInstanceC = new ProgramInstance( enrollmentDate, incidenDate, patientA, programC );
+        programInstanceC.setUid( "UID-C" );
+        programInstanceC.setStatus( ProgramInstance.STATUS_COMPLETED );
+
+        programInstanceD = new ProgramInstance( enrollmentDate, incidenDate, patientB, programA );
+        programInstanceD.setUid( "UID-D" );
+    }
+
+    @Test
+    public void testGetProgramInstancesByStatus()
+    {
+        programInstanceStore.save( programInstanceA );
+        programInstanceStore.save( programInstanceB );
+        programInstanceStore.save( programInstanceC );
+        programInstanceStore.save( programInstanceD );
+
+        Collection<ProgramInstance> programInstances = programInstanceStore.getByStatus( ProgramInstance.STATUS_ACTIVE );
+        assertEquals( 2, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+        assertTrue( programInstances.contains( programInstanceD ) );
+
+        programInstances = programInstanceStore.getByStatus( ProgramInstance.STATUS_CANCELLED );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceB ) );
+
+        programInstances = programInstanceStore.getByStatus( ProgramInstance.STATUS_COMPLETED );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceC ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByProgram()
+    {
+        programInstanceStore.save( programInstanceA );
+        programInstanceStore.save( programInstanceB );
+        programInstanceStore.save( programInstanceD );
+
+        Collection<ProgramInstance> programInstances = programInstanceStore.get( programA );
+        assertEquals( 2, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+        assertTrue( programInstances.contains( programInstanceD ) );
+
+        programInstances = programInstanceStore.get( programB );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceB ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByProgramList()
+    {
+        programInstanceStore.save( programInstanceA );
+        programInstanceStore.save( programInstanceB );
+        programInstanceStore.save( programInstanceC );
+        programInstanceStore.save( programInstanceD );
+
+        Collection<Program> programs = new HashSet<Program>();
+        programs.add( programA );
+        programs.add( programB );
+
+        Collection<ProgramInstance> programInstances = programInstanceStore.get( programs );
+        assertEquals( 3, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+        assertTrue( programInstances.contains( programInstanceB ) );
+        assertTrue( programInstances.contains( programInstanceD ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByOuProgramList()
+    {
+        programInstanceStore.save( programInstanceA );
+        programInstanceStore.save( programInstanceB );
+        programInstanceStore.save( programInstanceC );
+        programInstanceStore.save( programInstanceD );
+
+        Collection<Program> programs = new HashSet<Program>();
+        programs.add( programA );
+        programs.add( programB );
+
+        Collection<ProgramInstance> programInstances = programInstanceStore.get( programs, organisationUnitA );
+        assertEquals( 2, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+        assertTrue( programInstances.contains( programInstanceB ) );
+
+        programInstances = programInstanceStore.get( programs, organisationUnitB );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceD ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByOuProgramListStatus()
+    {
+        programInstanceStore.save( programInstanceA );
+        programInstanceStore.save( programInstanceB );
+        programInstanceStore.save( programInstanceC );
+
+        Collection<Program> programs = new HashSet<Program>();
+        programs.add( programA );
+        programs.add( programB );
+        programs.add( programC );
+
+        Collection<ProgramInstance> programInstances = programInstanceStore.get( programs, organisationUnitA,
+            ProgramInstance.STATUS_ACTIVE );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+
+        programInstances = programInstanceStore.get( programs, organisationUnitA, ProgramInstance.STATUS_COMPLETED );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceC ) );
+
+    }
+
+    @Test
+    public void testGetProgramInstancesByProgramStatus()
+    {
+        programInstanceStore.save( programInstanceA );
+        programInstanceStore.save( programInstanceB );
+        programInstanceStore.save( programInstanceC );
+        programInstanceStore.save( programInstanceD );
+
+        Collection<ProgramInstance> programInstances = programInstanceStore.get( programA,
+            ProgramInstance.STATUS_ACTIVE );
+        assertEquals( 2, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+        assertTrue( programInstances.contains( programInstanceD ) );
+
+        programInstances = programInstanceStore.get( programB, ProgramInstance.STATUS_CANCELLED );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceB ) );
+
+        programInstances = programInstanceStore.get( programC, ProgramInstance.STATUS_COMPLETED );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceC ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByProgramListStatus()
+    {
+        programInstanceStore.save( programInstanceA );
+        programInstanceStore.save( programInstanceB );
+        programInstanceStore.save( programInstanceC );
+        programInstanceStore.save( programInstanceD );
+
+        Collection<Program> programs = new HashSet<Program>();
+        programs.add( programA );
+        programs.add( programB );
+
+        Collection<ProgramInstance> programInstances = programInstanceStore.get( programs,
+            ProgramInstance.STATUS_ACTIVE );
+        assertEquals( 2, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+        assertTrue( programInstances.contains( programInstanceD ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByPatientStatus()
+    {
+        programInstanceStore.save( programInstanceA );
+        programInstanceStore.save( programInstanceD );
+
+        Collection<Program> programs = new HashSet<Program>();
+        programs.add( programA );
+        programs.add( programB );
+
+        Collection<ProgramInstance> programInstances = programInstanceStore.get( patientA,
+            ProgramInstance.STATUS_ACTIVE );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByPatientProgramStatus()
+    {
+        programInstanceStore.save( programInstanceA );
+        programInstanceStore.save( programInstanceB );
+        programInstanceStore.save( programInstanceC );
+        programInstanceStore.save( programInstanceD );
+
+        Collection<ProgramInstance> programInstances = programInstanceStore.get( patientA, programC,
+            ProgramInstance.STATUS_COMPLETED );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceC ) );
+
+        programInstances = programInstanceStore.get( patientA, programA, ProgramInstance.STATUS_ACTIVE );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByOuProgram()
+    {
+        programInstanceStore.save( programInstanceA );
+        programInstanceStore.save( programInstanceC );
+        programInstanceStore.save( programInstanceD );
+
+        Collection<ProgramInstance> programInstances = programInstanceStore.get( programA, organisationUnitA, 0, 10 );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesbyProgramOuPeriod()
+    {
+        programInstanceStore.save( programInstanceA );
+        programInstanceStore.save( programInstanceD );
+
+        Collection<ProgramInstance> programInstances = programInstanceStore.get( programA, organisationUnitA,
+            incidenDate, enrollmentDate );
+        assertEquals( 1, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+    }
+
+    @Test
+    public void testGetProgramInstancesByOuListProgramPeriod()
+    {
+        programInstanceStore.save( programInstanceA );
+        programInstanceStore.save( programInstanceB );
+        programInstanceStore.save( programInstanceD );
+
+        Collection<ProgramInstance> programInstances = programInstanceStore.get( programA, orgunitIds, incidenDate,
+            enrollmentDate, null, null );
+        assertEquals( 2, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+        assertTrue( programInstances.contains( programInstanceD ) );
+    }
+
+    @Test
+    public void testCountProgramInstancesByOuListProgramPeriod()
+    {
+        programInstanceStore.save( programInstanceA );
+        programInstanceStore.save( programInstanceB );
+        programInstanceStore.save( programInstanceD );
+
+        int count = programInstanceStore.count( programA, orgunitIds, incidenDate, enrollmentDate );
+        assertEquals( 2, count );
+    }
+
+    @Test
+    public void testGetProgramInstancesByOuListProgramStatusPeriod()
+    {
+        programInstanceStore.save( programInstanceA );
+        programInstanceStore.save( programInstanceB );
+        programInstanceStore.save( programInstanceD );
+
+        Collection<ProgramInstance> programInstances = programInstanceStore.getByStatus( ProgramInstance.STATUS_ACTIVE,
+            programA, orgunitIds, incidenDate, enrollmentDate );
+        assertEquals( 2, programInstances.size() );
+        assertTrue( programInstances.contains( programInstanceA ) );
+        assertTrue( programInstances.contains( programInstanceD ) );
+    }
+
+    @Test
+    public void testCountProgramInstancesByStatus()
+    {
+        programInstanceStore.save( programInstanceA );
+        programInstanceStore.save( programInstanceB );
+        programInstanceStore.save( programInstanceD );
+
+        int count = programInstanceStore.countByStatus( ProgramInstance.STATUS_ACTIVE, programA, orgunitIds,
+            incidenDate, enrollmentDate );
+        assertEquals( 2, count );
+    }
+
+}

=== modified file 'dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/DhisConvenienceTest.java'
--- dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/DhisConvenienceTest.java	2013-11-07 05:44:33 +0000
+++ dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/DhisConvenienceTest.java	2013-11-14 08:17:57 +0000
@@ -970,6 +970,7 @@
         program.setDateOfEnrollmentDescription( "DateOfEnrollmentDescription" );
         program.setDateOfIncidentDescription( "DateOfIncidentDescription" );
         program.setProgramStages( programStages );
+        program.setType( Program.MULTIPLE_EVENTS_WITH_REGISTRATION );
 
         for ( ProgramStage programStage : programStages )
         {
@@ -1077,7 +1078,7 @@
 
         return patientAttribute;
     }
-    
+
     /**
      * @param uniqueCharacter A unique character to identify the object.
      * @return PatientAttribute
@@ -1092,11 +1093,13 @@
 
         return patientAttribute;
     }
+
     /**
      * @param uniqueCharacter A unique character to identify the object.
      * @return PatientAttributeOption
      */
-    public static PatientAttributeOption createPatientAttributeOption( char uniqueChar, PatientAttribute patientAttribute )
+    public static PatientAttributeOption createPatientAttributeOption( char uniqueChar,
+        PatientAttribute patientAttribute )
     {
         PatientAttributeOption patientAttributeOption = new PatientAttributeOption();
 

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/program/UpdateProgramAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/program/UpdateProgramAction.java	2013-09-27 17:04:23 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/program/UpdateProgramAction.java	2013-11-14 08:17:57 +0000
@@ -443,14 +443,15 @@
                 reminder.setUserGroup( null );
             }
 
-            if ( relatedProgramId != null )
-            {
-                Program relatedProgram = programService.getProgram( relatedProgramId );
-                program.setRelatedProgram( relatedProgram );
-            }
-
             patientReminders.add( reminder );
         }
+
+        if ( relatedProgramId != null )
+        {
+            Program relatedProgram = programService.getProgram( relatedProgramId );
+            program.setRelatedProgram( relatedProgram );
+        }
+
         program.setPatientReminders( patientReminders );
 
         programService.updateProgram( program );