← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 10511: Add function to allow to define tamplete messages for program-instance and send them automatically.

 

------------------------------------------------------------
revno: 10511
committer: Tran Chau <tran.hispvietnam@xxxxxxxxx>
branch nick: dhis2
timestamp: Wed 2013-04-10 15:45:43 +0700
message:
  Add function to allow to define tamplete messages for program-instance and send them automatically.
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/patient/PatientReminder.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/Program.java
  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-api/src/main/java/org/hisp/dhis/program/ProgramStage.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/SchedulingProgramObject.java
  dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/patient/scheduling/SendScheduledMessageTask.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-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/hibernate/HibernateProgramStageInstanceStore.java
  dhis-2/dhis-services/dhis-service-patient/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-services/dhis-service-patient/src/main/resources/org/hisp/dhis/program/hibernate/Program.hbm.xml
  dhis-2/dhis-services/dhis-service-patient/src/main/resources/org/hisp/dhis/program/hibernate/ProgramInstance.hbm.xml
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/program/AddProgramAction.java
  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/schedule/ExecuteSendMessageAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/resources/org/hisp/dhis/patient/i18n_module.properties
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/addProgramForm.vm
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/javascript/program.js
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/updateProgramForm.vm


--
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/patient/PatientReminder.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/patient/PatientReminder.java	2013-02-13 03:00:36 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/patient/PatientReminder.java	2013-04-10 08:45:43 +0000
@@ -38,6 +38,26 @@
 {
     private static final long serialVersionUID = 3101502417481903219L;
 
+    public static final String TEMPLATE_MESSSAGE_PATIENT_NAME = "{patient-name}";
+
+    public static final String TEMPLATE_MESSSAGE_PROGRAM_NAME = "{program-name}";
+
+    public static final String TEMPLATE_MESSSAGE_PROGAM_STAGE_NAME = "{program-stage-name}";
+
+    public static final String TEMPLATE_MESSSAGE_DUE_DATE = "{due-date}";
+
+    public static final String TEMPLATE_MESSSAGE_ORGUNIT_NAME = "{orgunit-name}";
+
+    public static final String TEMPLATE_MESSSAGE_DAYS_SINCE_DUE_DATE = "{days-since-due-date}";
+
+    public static final String TEMPLATE_MESSSAGE_INCIDENT_DATE = "{incident-date}";
+
+    public static final String TEMPLATE_MESSSAGE_ENROLLMENT_DATE = "{enrollement-date}";
+
+    public static final String TEMPLATE_MESSSAGE_DAYS_SINCE_ENROLLMENT_DATE = "{days-since-enrollment-date}";
+
+    public static final String TEMPLATE_MESSSAGE_DAYS_SINCE_INCIDENT_DATE = "{days-since-incident-date}";
+
     private int id;
 
     private String name;

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/Program.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/Program.java	2013-04-10 04:22:14 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/Program.java	2013-04-10 08:45:43 +0000
@@ -40,6 +40,7 @@
 import org.hisp.dhis.patient.Patient;
 import org.hisp.dhis.patient.PatientAttribute;
 import org.hisp.dhis.patient.PatientIdentifierType;
+import org.hisp.dhis.patient.PatientReminder;
 import org.hisp.dhis.user.UserAuthorityGroup;
 import org.hisp.dhis.validation.ValidationCriteria;
 
@@ -119,6 +120,8 @@
      */
     private Boolean remindCompleted = false;
 
+    private Set<PatientReminder> patientReminders = new HashSet<PatientReminder>();
+
     // -------------------------------------------------------------------------
     // Constructors
     // -------------------------------------------------------------------------
@@ -490,4 +493,14 @@
         this.onlyEnrollOnce = onlyEnrollOnce;
     }
 
+    public Set<PatientReminder> getPatientReminders()
+    {
+        return patientReminders;
+    }
+
+    public void setPatientReminders( Set<PatientReminder> patientReminders )
+    {
+        this.patientReminders = patientReminders;
+    }
+
 }

=== 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-04-10 04:22:14 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramInstance.java	2013-04-10 08:45:43 +0000
@@ -36,10 +36,12 @@
 import org.hisp.dhis.common.view.DetailedView;
 import org.hisp.dhis.common.view.ExportView;
 import org.hisp.dhis.patient.Patient;
+import org.hisp.dhis.sms.outbound.OutboundSms;
 
 import java.io.Serializable;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -50,12 +52,12 @@
 public class ProgramInstance
     implements Serializable
 {
-   public static int STATUS_ACTIVE = 0;
-   
-   public static int STATUS_COMPLETED = 1;
-   
-   public static int STATUS_CANCELLED = 2;
-   
+    public static int STATUS_ACTIVE = 0;
+
+    public static int STATUS_COMPLETED = 1;
+
+    public static int STATUS_CANCELLED = 2;
+
     /**
      * Determines if a de-serialized file is compatible with this class.
      */
@@ -68,7 +70,7 @@
     private Date enrollmentDate;
 
     private Date endDate;
-    
+
     private Integer status = STATUS_ACTIVE;
 
     private Patient patient;
@@ -76,7 +78,9 @@
     private Program program;
 
     private Set<ProgramStageInstance> programStageInstances = new HashSet<ProgramStageInstance>();
-    
+
+    private List<OutboundSms> outboundSms;
+
     // -------------------------------------------------------------------------
     // Constructors
     // -------------------------------------------------------------------------
@@ -92,7 +96,7 @@
         this.patient = patient;
         this.program = program;
     }
-    
+
     // -------------------------------------------------------------------------
     // Getters and setters
     // -------------------------------------------------------------------------
@@ -255,13 +259,12 @@
         this.endDate = endDate;
     }
 
-    
     /**
      * @return the status
      */
     @JsonProperty
     @JsonView( { DetailedView.class, ExportView.class } )
-    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )    
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
     public int getStatus()
     {
         return status.intValue();
@@ -271,7 +274,7 @@
     {
         this.status = status;
     }
-    
+
     /**
      * @return the patient
      */
@@ -324,6 +327,16 @@
         this.programStageInstances = programStageInstances;
     }
 
+    public List<OutboundSms> getOutboundSms()
+    {
+        return outboundSms;
+    }
+
+    public void setOutboundSms( List<OutboundSms> outboundSms )
+    {
+        this.outboundSms = outboundSms;
+    }
+
     // -------------------------------------------------------------------------
     // Convenience method
     // -------------------------------------------------------------------------
@@ -338,7 +351,7 @@
             {
                 return programInstanceStage;
             }
-            
+
             count++;
         }
 

=== 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-04-10 03:13:47 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramInstanceService.java	2013-04-10 08:45:43 +0000
@@ -96,5 +96,7 @@
         Collection<Integer> orgunitIds, Date startDate, Date endDate );
 
     void removeProgramEnrollment( ProgramInstance programInstance );
+    
+    Collection<SchedulingProgramObject> getSendMesssageEvents();
 
 }

=== 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-04-10 03:13:47 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramInstanceStore.java	2013-04-10 08:45:43 +0000
@@ -73,14 +73,12 @@
     
     int count( Program program, Collection<Integer> orgunitIds, Date startDate, Date endDate );
     
-//    Collection<ProgramInstance> getUnenrollment( Program program, Collection<Integer> orgunitIds, Date startDate, Date endDate );
-//    
-//    int countUnenrollment( Program program, Collection<Integer> orgunitIds, Date startDate, Date endDate );
-   
     void removeProgramEnrollment( ProgramInstance programInstance );
     
     int countByStatus( Integer status, Program program, Collection<Integer> orgunitIds, Date startDate, Date endDate );
     
     Collection<ProgramInstance> getByStatus( Integer status, Program program, Collection<Integer> orgunitIds,
         Date startDate, Date endDate );
+    
+    Collection<SchedulingProgramObject> getSendMesssageEvents();
 }

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramStage.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramStage.java	2013-03-01 14:09:05 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramStage.java	2013-04-10 08:45:43 +0000
@@ -53,19 +53,7 @@
     public static final String TYPE_SECTION = "section";
 
     public static final String TYPE_CUSTOM = "custom";
-
-    public static final String TEMPLATE_MESSSAGE_PATIENT_NAME = "{patient-name}";
-
-    public static final String TEMPLATE_MESSSAGE_PROGRAM_NAME = "{program-name}";
-
-    public static final String TEMPLATE_MESSSAGE_PROGAM_STAGE_NAME = "{program-stage-name}";
-
-    public static final String TEMPLATE_MESSSAGE_DUE_DATE = "{due-date}";
-
-    public static final String TEMPLATE_MESSSAGE_ORGUNIT_NAME = "{orgunit-name}";
-
-    public static final String TEMPLATE_MESSSAGE_DAYS_SINCE_DUE_DATE = "{days-since-due-date}";
-
+    
     /**
      * Determines if a de-serialized file is compatible with this class.
      */

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/SchedulingProgramObject.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/SchedulingProgramObject.java	2012-09-11 04:54:34 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/SchedulingProgramObject.java	2013-04-10 08:45:43 +0000
@@ -38,6 +38,8 @@
 
     private Integer programStageInstanceId;
 
+    private Integer programInstanceId;
+
     private String message;
 
     public SchedulingProgramObject()
@@ -82,4 +84,14 @@
         this.message = message;
     }
 
+    public Integer getProgramInstanceId()
+    {
+        return programInstanceId;
+    }
+
+    public void setProgramInstanceId( Integer programInstanceId )
+    {
+        this.programInstanceId = programInstanceId;
+    }
+
 }

=== modified file 'dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/patient/scheduling/SendScheduledMessageTask.java'
--- dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/patient/scheduling/SendScheduledMessageTask.java	2013-04-02 15:14:17 +0000
+++ dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/patient/scheduling/SendScheduledMessageTask.java	2013-04-10 08:45:43 +0000
@@ -32,6 +32,7 @@
 import java.util.Collection;
 import java.util.List;
 
+import org.hisp.dhis.program.ProgramInstanceService;
 import org.hisp.dhis.program.ProgramStageInstanceService;
 import org.hisp.dhis.program.SchedulingProgramObject;
 import org.hisp.dhis.sms.SmsServiceException;
@@ -55,6 +56,13 @@
         this.programStageInstanceService = programStageInstanceService;
     }
 
+    private ProgramInstanceService programInstanceService;
+
+    public void setProgramInstanceService( ProgramInstanceService programInstanceService )
+    {
+        this.programInstanceService = programInstanceService;
+    }
+
     private OutboundSmsService outboundSmsService;
 
     public void setOutboundSmsService( OutboundSmsService outboundSmsService )
@@ -72,7 +80,7 @@
     // -------------------------------------------------------------------------
     // Params
     // -------------------------------------------------------------------------
-
+    
     private Boolean sendingMessage;
 
     public void setSendingMessage( Boolean sendingMessage )
@@ -93,7 +101,8 @@
         }
         else
         {
-            scheduleMessage();
+            scheduleProgramStageInstanceMessage();
+            scheduleProgramInstanceMessage();
         }
     }
 
@@ -101,11 +110,11 @@
     // Supportive methods
     // -------------------------------------------------------------------------
 
-    private void scheduleMessage()
+    private void scheduleProgramStageInstanceMessage()
     {
         Collection<SchedulingProgramObject> schedulingProgramObjects = programStageInstanceService
             .getSendMesssageEvents();
-
+       
         for ( SchedulingProgramObject schedulingProgramObject : schedulingProgramObjects )
         {
             String message = schedulingProgramObject.getMessage();
@@ -129,6 +138,33 @@
             }
         }
     }
+    
+    private void scheduleProgramInstanceMessage()
+    {
+        Collection<SchedulingProgramObject> schedulingProgramObjects =  programInstanceService.getSendMesssageEvents();
+        
+        for ( SchedulingProgramObject schedulingProgramObject : schedulingProgramObjects )
+        {
+            String message = schedulingProgramObject.getMessage();
+            try
+            {
+                OutboundSms outboundSms = new OutboundSms( message, schedulingProgramObject.getPhoneNumber() );
+                outboundSms.setSender( DHIS_SYSTEM_SENDER );
+                outboundSmsService.saveOutboundSms( outboundSms );
+
+                String sql = "INSERT INTO programinstance_outboundsms"
+                    + "( programinstanceid, outboundsmsid, sort_order) VALUES " + "("
+                    + schedulingProgramObject.getProgramInstanceId() + ", " + outboundSms.getId() + ","
+                    + (System.currentTimeMillis() / 1000) + ") ";
+
+                jdbcTemplate.execute( sql );
+            }
+            catch ( SmsServiceException e )
+            {
+                message = e.getMessage();
+            }
+        }
+    }
 
     private void sendMessage()
     {

=== 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-04-10 03:13:47 +0000
+++ dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/DefaultProgramInstanceService.java	2013-04-10 08:45:43 +0000
@@ -359,29 +359,17 @@
     {
         return programInstanceStore.getByStatus( status, program, orgunitIds, startDate, endDate );
     }
-
-    // @Override
-    // public Collection<ProgramInstance> getUnenrollment( Program program,
-    // Collection<Integer> orgunitIds,
-    // Date startDate, Date endDate )
-    // {
-    // return programInstanceStore.getUnenrollment( program, orgunitIds,
-    // startDate, endDate );
-    // }
-    //
-    // @Override
-    // public int countUnenrollment( Program program, Collection<Integer>
-    // orgunitIds, Date startDate, Date endDate )
-    // {
-    // return programInstanceStore.countUnenrollment( program, orgunitIds,
-    // startDate, endDate );
-    // }
-
+    
     public void removeProgramEnrollment( ProgramInstance programInstance )
     {
         programInstanceStore.removeProgramEnrollment( programInstance );
     }
 
+    public Collection<SchedulingProgramObject> getSendMesssageEvents()
+    {
+        return programInstanceStore.getSendMesssageEvents();
+    }
+    
     // -------------------------------------------------------------------------
     // due-date && report-date
     // -------------------------------------------------------------------------

=== 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-04-10 03:13:47 +0000
+++ dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/hibernate/HibernateProgramInstanceStore.java	2013-04-10 08:45:43 +0000
@@ -29,6 +29,7 @@
 
 import java.util.Collection;
 import java.util.Date;
+import java.util.HashSet;
 
 import org.hibernate.criterion.Order;
 import org.hibernate.criterion.Projections;
@@ -36,10 +37,13 @@
 import org.hisp.dhis.hibernate.HibernateGenericStore;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.patient.Patient;
+import org.hisp.dhis.patient.PatientReminder;
 import org.hisp.dhis.program.Program;
 import org.hisp.dhis.program.ProgramInstance;
 import org.hisp.dhis.program.ProgramInstanceStore;
+import org.hisp.dhis.program.SchedulingProgramObject;
 import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.support.rowset.SqlRowSet;
 
 /**
  * @author Abyot Asalefew
@@ -241,4 +245,63 @@
         jdbcTemplate.execute( sql );
     }
 
+    public Collection<SchedulingProgramObject> getSendMesssageEvents()
+    {
+        String sql = "select pi.programinstanceid, p.phonenumber, prm.templatemessage, "
+            + "         p.firstname, p.middlename, p.lastname, 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 "
+            + "       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 INNER JOIN patientreminder prm "
+            + "              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.enrollmentdate) ) = prm.daysallowedsendmessage";
+        
+        SqlRowSet rs = jdbcTemplate.queryForRowSet( sql );
+
+        int cols = rs.getMetaData().getColumnCount();
+
+        Collection<SchedulingProgramObject> schedulingProgramObjects = new HashSet<SchedulingProgramObject>();
+
+        while ( rs.next() )
+        {
+            String message = "";
+            for ( int i = 1; i <= cols; i++ )
+            {
+
+                message = rs.getString( "templatemessage" );
+                String patientName = rs.getString( "firstName" );
+                String organisationunitName = rs.getString( "orgunitName" );
+                String programName = rs.getString( "programName" );
+                String incidentDate = rs.getString( "dateofincident" );
+                String daysSinceIncidentDate = rs.getString( "days_since_incident_date" );
+                String erollmentDate = rs.getString( "enrollmentdate" );
+                String daysSinceEnrollementDate = rs.getString( "days_since_erollment_date" );
+
+                message = message.replace( PatientReminder.TEMPLATE_MESSSAGE_PATIENT_NAME, patientName );
+                message = message.replace( PatientReminder.TEMPLATE_MESSSAGE_PROGRAM_NAME, programName );
+                message = message.replace( PatientReminder.TEMPLATE_MESSSAGE_ORGUNIT_NAME, organisationunitName );
+                message = message.replace( PatientReminder.TEMPLATE_MESSSAGE_INCIDENT_DATE, incidentDate );
+                message = message.replace( PatientReminder.TEMPLATE_MESSSAGE_ENROLLMENT_DATE, erollmentDate );
+                message = message.replace( PatientReminder.TEMPLATE_MESSSAGE_DAYS_SINCE_ENROLLMENT_DATE, daysSinceEnrollementDate );
+                message = message.replace( PatientReminder.TEMPLATE_MESSSAGE_DAYS_SINCE_INCIDENT_DATE, daysSinceIncidentDate );
+            }
+
+            SchedulingProgramObject schedulingProgramObject = new SchedulingProgramObject();
+            schedulingProgramObject.setProgramInstanceId( rs.getInt( "programinstanceid" ) );
+            schedulingProgramObject.setPhoneNumber( rs.getString( "phonenumber" ) );
+            schedulingProgramObject.setMessage( message );
+
+            schedulingProgramObjects.add( schedulingProgramObject );
+        }
+
+        return schedulingProgramObjects;
+    }
+
 }

=== modified file 'dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/hibernate/HibernateProgramStageInstanceStore.java'
--- dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/hibernate/HibernateProgramStageInstanceStore.java	2013-04-10 03:13:47 +0000
+++ dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/hibernate/HibernateProgramStageInstanceStore.java	2013-04-10 08:45:43 +0000
@@ -59,6 +59,7 @@
 import org.hisp.dhis.patient.Patient;
 import org.hisp.dhis.patient.PatientAudit;
 import org.hisp.dhis.patient.PatientAuditService;
+import org.hisp.dhis.patient.PatientReminder;
 import org.hisp.dhis.patient.PatientService;
 import org.hisp.dhis.patientreport.PatientAggregateReport;
 import org.hisp.dhis.patientreport.TabularReportColumn;
@@ -425,12 +426,12 @@
                 String daysSinceDueDate = rs.getString( "days_since_due_date" );
                 String dueDate = rs.getString( "duedate" );
 
-                message = message.replace( ProgramStage.TEMPLATE_MESSSAGE_PATIENT_NAME, patientName );
-                message = message.replace( ProgramStage.TEMPLATE_MESSSAGE_PROGRAM_NAME, programName );
-                message = message.replace( ProgramStage.TEMPLATE_MESSSAGE_PROGAM_STAGE_NAME, programStageName );
-                message = message.replace( ProgramStage.TEMPLATE_MESSSAGE_DUE_DATE, dueDate );
-                message = message.replace( ProgramStage.TEMPLATE_MESSSAGE_ORGUNIT_NAME, organisationunitName );
-                message = message.replace( ProgramStage.TEMPLATE_MESSSAGE_DAYS_SINCE_DUE_DATE, daysSinceDueDate );
+                message = message.replace( PatientReminder.TEMPLATE_MESSSAGE_PATIENT_NAME, patientName );
+                message = message.replace( PatientReminder.TEMPLATE_MESSSAGE_PROGRAM_NAME, programName );
+                message = message.replace( PatientReminder.TEMPLATE_MESSSAGE_PROGAM_STAGE_NAME, programStageName );
+                message = message.replace( PatientReminder.TEMPLATE_MESSSAGE_DUE_DATE, dueDate );
+                message = message.replace( PatientReminder.TEMPLATE_MESSSAGE_ORGUNIT_NAME, organisationunitName );
+                message = message.replace( PatientReminder.TEMPLATE_MESSSAGE_DAYS_SINCE_DUE_DATE, daysSinceDueDate );
             }
 
             SchedulingProgramObject schedulingProgramObject = new SchedulingProgramObject();

=== modified file 'dhis-2/dhis-services/dhis-service-patient/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-services/dhis-service-patient/src/main/resources/META-INF/dhis/beans.xml	2013-04-10 03:13:47 +0000
+++ dhis-2/dhis-services/dhis-service-patient/src/main/resources/META-INF/dhis/beans.xml	2013-04-10 08:45:43 +0000
@@ -448,6 +448,7 @@
 		<property name="programStageInstanceService" ref="org.hisp.dhis.program.ProgramStageInstanceService" />
         <property name="outboundSmsService" ref="org.hisp.dhis.sms.outbound.OutboundSmsService" />
         <property name="jdbcTemplate" ref="jdbcTemplate" />
+        <property name="programInstanceService" ref="org.hisp.dhis.program.ProgramInstanceService" />
     </bean>
 
 	<bean id="sendMessageScheduled"

=== modified file 'dhis-2/dhis-services/dhis-service-patient/src/main/resources/org/hisp/dhis/program/hibernate/Program.hbm.xml'
--- dhis-2/dhis-services/dhis-service-patient/src/main/resources/org/hisp/dhis/program/hibernate/Program.hbm.xml	2013-04-10 04:22:14 +0000
+++ dhis-2/dhis-services/dhis-service-patient/src/main/resources/org/hisp/dhis/program/hibernate/Program.hbm.xml	2013-04-10 08:45:43 +0000
@@ -76,6 +76,11 @@
 			
  	<property name="remindCompleted" />
  
+ 	<set name="patientReminders" order-by="daysAllowedSendMessage" cascade="all">
+      <key column="programid" />
+      <one-to-many class="org.hisp.dhis.patient.PatientReminder" />
+    </set>
+    
 	<!-- Access properties -->
 	
     <many-to-one name="user" class="org.hisp.dhis.user.User" column="userid" foreign-key="fk_program_userid" />

=== modified file 'dhis-2/dhis-services/dhis-service-patient/src/main/resources/org/hisp/dhis/program/hibernate/ProgramInstance.hbm.xml'
--- dhis-2/dhis-services/dhis-service-patient/src/main/resources/org/hisp/dhis/program/hibernate/ProgramInstance.hbm.xml	2013-04-10 03:13:47 +0000
+++ dhis-2/dhis-services/dhis-service-patient/src/main/resources/org/hisp/dhis/program/hibernate/ProgramInstance.hbm.xml	2013-04-10 08:45:43 +0000
@@ -28,6 +28,12 @@
       <key column="programinstanceid" />
       <one-to-many class="org.hisp.dhis.program.ProgramStageInstance" />
     </set>
+    
+    <list name="outboundSms" table="programinstance_outboundsms">
+      <key column="programinstanceid" />
+      <list-index column="sort_order" base="1" />
+      <many-to-many class="org.hisp.dhis.sms.outbound.OutboundSms" column="outboundsmsid" />
+    </list>
 
   </class>
 </hibernate-mapping>

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/program/AddProgramAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/program/AddProgramAction.java	2013-04-10 04:22:14 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/program/AddProgramAction.java	2013-04-10 08:45:43 +0000
@@ -29,13 +29,16 @@
 
 import java.util.ArrayList;
 import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import org.hisp.dhis.patient.Patient;
 import org.hisp.dhis.patient.PatientAttribute;
 import org.hisp.dhis.patient.PatientAttributeService;
 import org.hisp.dhis.patient.PatientIdentifierType;
 import org.hisp.dhis.patient.PatientIdentifierTypeService;
+import org.hisp.dhis.patient.PatientReminder;
 import org.hisp.dhis.program.Program;
 import org.hisp.dhis.program.ProgramInstance;
 import org.hisp.dhis.program.ProgramInstanceService;
@@ -190,14 +193,27 @@
         this.onlyEnrollOnce = onlyEnrollOnce;
     }
 
-
     private Boolean remindCompleted = false;
 
     public void setRemindCompleted( Boolean remindCompleted )
     {
         this.remindCompleted = remindCompleted;
     }
-    
+
+    private List<Integer> daysAllowedSendMessages = new ArrayList<Integer>();
+
+    public void setDaysAllowedSendMessages( List<Integer> daysAllowedSendMessages )
+    {
+        this.daysAllowedSendMessages = daysAllowedSendMessages;
+    }
+
+    private List<String> templateMessages = new ArrayList<String>();
+
+    public void setTemplateMessages( List<String> templateMessages )
+    {
+        this.templateMessages = templateMessages;
+    }
+
     // -------------------------------------------------------------------------
     // Action implementation
     // -------------------------------------------------------------------------
@@ -268,6 +284,16 @@
         program.setPatientIdentifierTypes( identifierTypes );
         program.setPatientAttributes( patientAttributes );
 
+        // Template messasges
+        Set<PatientReminder> patientReminders = new HashSet<PatientReminder>();
+        for ( int i = 0; i < daysAllowedSendMessages.size(); i++ )
+        {
+            PatientReminder reminder = new PatientReminder( "", daysAllowedSendMessages.get( i ),
+                templateMessages.get( i ) );
+            patientReminders.add( reminder );
+        }
+        program.setPatientReminders( patientReminders );
+        
         programService.saveProgram( program );
 
         if ( program.getType().equals( Program.SINGLE_EVENT_WITH_REGISTRATION )

=== 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-04-10 04:22:14 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/program/UpdateProgramAction.java	2013-04-10 08:45:43 +0000
@@ -28,13 +28,16 @@
 package org.hisp.dhis.patient.action.program;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import org.hisp.dhis.patient.Patient;
 import org.hisp.dhis.patient.PatientAttribute;
 import org.hisp.dhis.patient.PatientAttributeService;
 import org.hisp.dhis.patient.PatientIdentifierType;
 import org.hisp.dhis.patient.PatientIdentifierTypeService;
+import org.hisp.dhis.patient.PatientReminder;
 import org.hisp.dhis.program.Program;
 import org.hisp.dhis.program.ProgramService;
 
@@ -193,6 +196,20 @@
         this.remindCompleted = remindCompleted;
     }
 
+    private List<Integer> daysAllowedSendMessages = new ArrayList<Integer>();
+
+    public void setDaysAllowedSendMessages( List<Integer> daysAllowedSendMessages )
+    {
+        this.daysAllowedSendMessages = daysAllowedSendMessages;
+    }
+
+    private List<String> templateMessages = new ArrayList<String>();
+
+    public void setTemplateMessages( List<String> templateMessages )
+    {
+        this.templateMessages = templateMessages;
+    }
+
     // -------------------------------------------------------------------------
     // Action implementation
     // -------------------------------------------------------------------------
@@ -260,6 +277,16 @@
         program.setPatientIdentifierTypes( identifierTypes );
         program.setPatientAttributes( patientAttributes );
 
+        // Template messasges
+        Set<PatientReminder> patientReminders = new HashSet<PatientReminder>();
+        for ( int i = 0; i < daysAllowedSendMessages.size(); i++ )
+        {
+            PatientReminder reminder = new PatientReminder( "", daysAllowedSendMessages.get( i ),
+                templateMessages.get( i ) );
+            patientReminders.add( reminder );
+        }
+        program.setPatientReminders( patientReminders );
+
         programService.updateProgram( program );
 
         return SUCCESS;

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/schedule/ExecuteSendMessageAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/schedule/ExecuteSendMessageAction.java	2012-10-22 04:00:47 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/schedule/ExecuteSendMessageAction.java	2013-04-10 08:45:43 +0000
@@ -31,6 +31,7 @@
 
 import java.util.Collection;
 
+import org.hisp.dhis.program.ProgramInstanceService;
 import org.hisp.dhis.program.ProgramStageInstanceService;
 import org.hisp.dhis.program.SchedulingProgramObject;
 import org.hisp.dhis.sms.SmsServiceException;
@@ -59,6 +60,13 @@
         this.programStageInstanceService = programStageInstanceService;
     }
 
+    private ProgramInstanceService programInstanceService;
+
+    public void setProgramInstanceService( ProgramInstanceService programInstanceService )
+    {
+        this.programInstanceService = programInstanceService;
+    }
+
     private JdbcTemplate jdbcTemplate;
 
     public void setJdbcTemplate( JdbcTemplate jdbcTemplate )
@@ -80,8 +88,39 @@
     @Override
     public String execute()
     {
-        Collection<SchedulingProgramObject> schedulingProgramObjects = programStageInstanceService
-            .getSendMesssageEvents();
+        // ---------------------------------------------------------------------
+        // Send program-instance messages
+        // ---------------------------------------------------------------------
+
+        Collection<SchedulingProgramObject> schedulingProgramObjects = programInstanceService.getSendMesssageEvents();
+
+        for ( SchedulingProgramObject schedulingProgramObject : schedulingProgramObjects )
+        {
+            String message = schedulingProgramObject.getMessage();
+            try
+            {
+                OutboundSms outboundSms = new OutboundSms( message, schedulingProgramObject.getPhoneNumber() );
+                outboundSms.setSender( DHIS_SYSTEM_SENDER );
+                outboundSmsService.saveOutboundSms( outboundSms );
+
+                String sql = "INSERT INTO programinstance_outboundsms"
+                    + "( programinstanceid, outboundsmsid, sort_order) VALUES " + "("
+                    + schedulingProgramObject.getProgramInstanceId() + ", " + outboundSms.getId() + ","
+                    + (System.currentTimeMillis() / 1000) + ") ";
+
+                jdbcTemplate.execute( sql );
+            }
+            catch ( SmsServiceException e )
+            {
+                message = e.getMessage();
+            }
+        }
+
+        // ---------------------------------------------------------------------
+        // Send program-stage-instance messages
+        // ---------------------------------------------------------------------
+
+        schedulingProgramObjects = programStageInstanceService.getSendMesssageEvents();
 
         for ( SchedulingProgramObject schedulingProgramObject : schedulingProgramObjects )
         {
@@ -99,7 +138,7 @@
                     + "( programstageinstanceid, outboundsmsid, sort_order) VALUES " + "("
                     + schedulingProgramObject.getProgramStageInstanceId() + ", " + outboundSms.getId() + ","
                     + (System.currentTimeMillis() / 1000) + ") ";
-                
+
                 jdbcTemplate.execute( sql );
             }
             catch ( SmsServiceException e )

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/resources/META-INF/dhis/beans.xml	2013-04-08 09:24:43 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/resources/META-INF/dhis/beans.xml	2013-04-10 08:45:43 +0000
@@ -1046,6 +1046,8 @@
 		scope="prototype">
 		<property name="programStageInstanceService"
 			ref="org.hisp.dhis.program.ProgramStageInstanceService" />
+		<property name="programInstanceService"
+			ref="org.hisp.dhis.program.ProgramInstanceService" />
 		<property name="jdbcTemplate" ref="jdbcTemplate" />
 		<property name="outboundSmsService"
 			ref="org.hisp.dhis.sms.outbound.OutboundSmsService" />

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/resources/org/hisp/dhis/patient/i18n_module.properties'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/resources/org/hisp/dhis/patient/i18n_module.properties	2013-04-10 04:22:14 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/resources/org/hisp/dhis/patient/i18n_module.properties	2013-04-10 08:45:43 +0000
@@ -375,4 +375,8 @@
 save_unsuccess = Save unsuccessfully
 validate_form = Validate form
 validate_success = The registration form passed validation successfully
-remind_completing_program_after_program_stage_completed = Remind completing program after a program stage completed
\ No newline at end of file
+remind_completing_program_after_program_stage_completed = Remind completing program after a program stage completed
+days_since_enrollment_date = Days since enrollment date
+days_before_after_enrollment_date = Days before/after enrollment date
+enrollement_date = Enrollement date
+incident_date = Incident date
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/addProgramForm.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/addProgramForm.vm	2013-04-10 04:22:14 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/addProgramForm.vm	2013-04-10 08:45:43 +0000
@@ -1,9 +1,50 @@
+<script>
+	jQuery( document ).ready( function()
+{
+	validation( 'addProgramForm', function( form ){ 
+		if( duplicate==true) 
+			return false;
+		else
+			form.submit();
+	}, function(){
+		duplicate = false;
+		var COLOR_RED = '#ff8a8a';
+		jQuery(".daysAllowedSendMessage").each( function( i, a ){ 
+			jQuery(".daysAllowedSendMessage").each( function(j, b){ 
+				if( i!=j && a.value==b.value){
+					jQuery( a ).css( 'background-color', COLOR_RED );
+					jQuery( b ).css( 'background-color', COLOR_RED );
+					duplicate = true;
+				}
+			});
+		});
+		
+		var daysAllowedSendMessages = jQuery( "#daysAllowedSendMessages" );
+		daysAllowedSendMessages.empty();
+		
+		var templateMessages = jQuery( "#templateMessages" );
+		templateMessages.empty();
+		
+		jQuery(".daysAllowedSendMessage").each( function( i, item ){ 
+			daysAllowedSendMessages.append( "<option value='" + item.value + "' selected='true'>" + item.value +"</option>" );
+		});
+		jQuery(".templateMessage").each( function( i, item ){ 
+			templateMessages.append( "<option value='" + item.value + "' selected='true'>" +item.value+"</option>" );
+		});
+	});
+	
+	checkValueIsExist( "name", "validateProgram.action" );	
+});
+</script>
+
 <script type="text/javascript" src="javascript/addProgramForm.js"></script>
 
 <h3>$i18n.getString( "create_new_program" )</h3>
 									
 <form id="addProgramForm" name="addProgramForm" action="addProgram.action" method="post" >
 
+<select id='daysAllowedSendMessages' name="daysAllowedSendMessages" multiple="multiple" class="hidden"></select>
+<select id='templateMessages' name="templateMessages" multiple="multiple" class="hidden"></select>
 <table>	 
 	<thead>
       <tr>
@@ -158,6 +199,20 @@
 	</tr>
 </table>
 
+<table id='programMessageTB'>
+	<tr>
+		<th colspan='3'>$i18n.getString("template_reminder_message")</th>
+	</tr>
+	<tbody id='programStageMessage'>
+	</tbody>
+	<tr>
+		<td></td>
+		<td>
+			<input type="button" value="$i18n.getString('add_more')" onclick='generateTemplateMessageForm();'>
+		</td>
+	</tr>
+</table>
+
 <table>
 	<tr>
 		<td colspan='3'>
@@ -166,4 +221,20 @@
 		</td>
 	</tr>
 </table>
-</form>
\ No newline at end of file
+</form>
+
+<script>
+	var i18n_reminder = '$encoder.jsEscape( $i18n.getString( "reminder" ) , "'")';   
+	var i18n_remove_reminder = '$encoder.jsEscape( $i18n.getString( "remove_reminder" ) , "'")';   
+	var i18n_days_before_after_enrollment_date = '$encoder.jsEscape( $i18n.getString( "days_before_after_enrollment_date" ) , "'")';   
+	var i18n_params = '$encoder.jsEscape( $i18n.getString( "params" ) , "'")';   
+	var i18n_patient_name = '$encoder.jsEscape( $i18n.getString( "patient_name" ) , "'")';   
+	var i18n_program_name = '$encoder.jsEscape( $i18n.getString( "program_name" ) , "'")';   
+	var i18n_incident_date = '$encoder.jsEscape( $i18n.getString( "incident_date" ) , "'")';   
+	var i18n_days_since_incident_date = '$encoder.jsEscape( $i18n.getString( "days_since_incident_date" ) , "'")';   
+	var i18n_orgunit_name = '$encoder.jsEscape( $i18n.getString( "orgunit_name" ) , "'")';   
+	var i18n_enrollement_date = '$encoder.jsEscape( $i18n.getString( "enrollement_date" ) , "'")';   
+	var i18n_days_since_enrollment_date = '$encoder.jsEscape( $i18n.getString( "days_since_enrollment_date" ) , "'")';   
+	var i18n_message = '$encoder.jsEscape( $i18n.getString( "message" ) , "'")';   
+	var i18n_name_exists = '$encoder.jsEscape( $i18n.getString( "name_exists" ) , "'")';   
+</script>

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/javascript/program.js'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/javascript/program.js	2013-04-10 04:22:14 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/javascript/program.js	2013-04-10 08:45:43 +0000
@@ -71,7 +71,9 @@
 		disable("generatedByEnrollmentDate");
 		disable("availablePropertyIds");
 		disable('ignoreOverdueEvents');
-		hideById("selectedList");
+		hideById('selectedList');
+		hideById('programMessageTB');
+		
 		jQuery("[name=displayed]").attr("disabled", true);
 		jQuery("[name=displayed]").removeAttr("checked");
 		
@@ -81,11 +83,12 @@
 		enable('onlyEnrollOnce');
 		jQuery("[name=displayed]").prop("disabled", false);
 		enable("availablePropertyIds");
-		showById("selectedList");
 		enable("generatedByEnrollmentDate");
 		enable('dateOfEnrollmentDescription');
 		enable("displayIncidentDate");
 		enable('ignoreOverdueEvents');
+		showById('programMessageTB');
+		showById("selectedList");
 		
 		jQuery("[name=nonAnonymous]").show();
 		if( type == 2 ){
@@ -246,4 +249,52 @@
 			}
 		}
 	}
+}
+
+// --------------------------------------------------------------------
+// Generate template message form
+// --------------------------------------------------------------------
+
+function generateTemplateMessageForm()
+{
+	var rowId = jQuery('.daysAllowedSendMessage').length + 1;
+	
+	var contend = '<tr name="tr' + rowId + '" class="listAlternateRow" >'
+				+ 	'<td colspan="2">' + i18n_reminder + ' ' + rowId + '<a href="javascript:removeTemplateMessageForm('+ rowId +')"> ( '+ i18n_remove_reminder + ' )</a></td>'
+				+ '</tr>'
+				+ '<tr name="tr' + rowId + '">'
+				+ 	'<td><label>' + i18n_days_before_after_enrollment_date + '</label></td>'
+				+ 	'<td><input type="text" id="daysAllowedSendMessage' + rowId + '" name="daysAllowedSendMessage' + rowId + '" class="daysAllowedSendMessage {validate:{required:true,number:true}}"/></td>'
+				+ '</tr>'
+				+ '<tr name="tr' + rowId + '">'
+				+	'<td>' + i18n_params + '</td>'
+				+	'<td>'
+				+		'<select multiple size="4" id="params' + rowId +'" name="params" ondblclick="insertParams(this.value, ' + rowId + ');">'
+				+			'<option value="{patient-name}">' + i18n_patient_name + '</option>'
+				+			'<option value="{program-name}">' + i18n_program_name + '</option>'
+				+			'<option value="{incident-date}">' + i18n_incident_date + '</option>'
+				+			'<option value="{days-since-incident-date}">' + i18n_days_since_incident_date + '</option>'
+				+			'<option value="{enrollement-date}">' + i18n_enrollement_date + '</option>'
+				+			'<option value="{days-since-enrollement-date}">' + i18n_days_since_enrollment_date + '</option>'
+				+			'<option value="{orgunit-name}">' + i18n_orgunit_name + '</option>'
+				+		'</select>'
+				+	'</td>'
+				+ '</tr>'
+				+ '<tr name="tr' + rowId + '">'
+				+	'<td><label>' + i18n_message + '</label></td>'
+				+	'<td><textarea id="templateMessage' + rowId + '" name="templateMessage' + rowId + '" style="width:320px" class="templateMessage {validate:{required:true, rangelength:[3,160]}}"></textarea></td>'
+				+ '</tr>';
+
+	jQuery('#programStageMessage').append( contend );
+}
+
+function removeTemplateMessageForm( rowId )
+{
+	jQuery("[name=tr" + rowId + "]").remove();
+}
+
+function insertParams( paramValue, rowId )
+{
+	var templateMessage = paramValue;
+	insertTextCommon('templateMessage' + rowId, templateMessage);
 }
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/updateProgramForm.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/updateProgramForm.vm	2013-04-10 04:22:14 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/updateProgramForm.vm	2013-04-10 08:45:43 +0000
@@ -1,8 +1,49 @@
+<script>
+	jQuery( document ).ready( function()
+{
+	validation( 'updateProgramForm', function( form ){ 
+		if( duplicate==true) 
+			return false;
+		else
+			form.submit();
+	}, function(){
+		duplicate = false;
+		var COLOR_RED = '#ff8a8a';
+		jQuery(".daysAllowedSendMessage").each( function( i, a ){ 
+			jQuery(".daysAllowedSendMessage").each( function(j, b){ 
+				if( i!=j && a.value==b.value){
+					jQuery( a ).css( 'background-color', COLOR_RED );
+					jQuery( b ).css( 'background-color', COLOR_RED );
+					duplicate = true;
+				}
+			});
+		});
+		
+		var daysAllowedSendMessages = jQuery( "#daysAllowedSendMessages" );
+		daysAllowedSendMessages.empty();
+		
+		var templateMessages = jQuery( "#templateMessages" );
+		templateMessages.empty();
+		
+		jQuery(".daysAllowedSendMessage").each( function( i, item ){ 
+			daysAllowedSendMessages.append( "<option value='" + item.value + "' selected='true'>" + item.value +"</option>" );
+		});
+		jQuery(".templateMessage").each( function( i, item ){ 
+			templateMessages.append( "<option value='" + item.value + "' selected='true'>" +item.value+"</option>" );
+		});
+	});
+	
+	checkValueIsExist( "name", "validateProgram.action",{id:getFieldValue('id')} );	
+});
+</script>
+
 <script type="text/javascript" src="javascript/updateProgramForm.js"></script>
 
 <h3>$i18n.getString( "edit_program" )</h3>
 
 <form id="updateProgramForm" name="updateProgramForm" action="updateProgram.action" method="post" onsubmit="selectAllById('selectedPropertyIds');" >
+  <select id='daysAllowedSendMessages' name="daysAllowedSendMessages" multiple="multiple" class="hidden"></select>
+  <select id='templateMessages' name="templateMessages" multiple="multiple" class="hidden"></select>
   <input type="hidden" id="id" name="id" value="$program.id">
   <table id="detailsList">
     <thead>
@@ -178,6 +219,56 @@
 	  </tr>
     </tbody>
   </table>  
+  
+  #if($program.type!=3)
+	<table>
+		<tr>
+			<th colspan='3'>$i18n.getString("template_reminder_message")</th>
+		</tr>
+		<tbody id='programStageMessage'>
+			#set($index = 0)
+			#foreach($reminder in $program.patientReminders)
+				#set($index = $index + 1)
+				<tr name="tr$index" class="listAlternateRow" >
+					<td colspan='2'>
+						$i18n.getString( "reminder" ) $index
+						<span style="align:right"><a href='javascript:removeTemplateMessageForm($index)'> ( $i18n.getString("remove_reminder") )</a>
+					</td>
+				</tr>
+				<tr name="tr$index">
+					<td><label>$i18n.getString( "days_before_after_due_date" )</label></td>
+					<td><input type="text" id="daysAllowedSendMessage$index" name="daysAllowedSendMessage$index" class="daysAllowedSendMessage {validate:{required:true,number:true}}" value="$!reminder.daysAllowedSendMessage"/></td>
+				</tr>
+				<tr name="tr$index">
+					<td>$i18n.getString( "params" )</td>
+					<td>
+						<select multiple size='4' ondblclick="insertParams(this.value, $index);">
+							<option value="{patient-name}">$i18n.getString("patient_name")</option>
+							<option value="{program-name}">$i18n.getString("program_name")</option>
+							<option value="{incident-date}">$i18n.getString("incident_date")</option>
+							<option value="{days-since-incident-date}">$i18n.getString("days_since_incident_date")</option>
+							<option value="{enrollement-date}">$i18n.getString("enrollement_date")</option>
+							<option value="{days-since-enrollement-date}">$i18n.getString("days_since_enrollment_date")</option>
+							<option value="{orgunit-name}">$i18n.getString("orgunit_name")</option>
+						</select>
+					</td>
+				</tr>
+				<tr name="tr$index">
+					<td><label>$i18n.getString( "message" )</label></td>
+					<td><textarea id="templateMessage$index" name="templateMessage$index" style="width:320px" class="templateMessage {validate:{required:true, rangelength:[3,160]}}">$reminder.templateMessage</textarea></td>
+				</tr>
+			#end
+		</tbody>
+		
+		<tr>
+			<td></td>
+			<td>
+				<input type="button" value="$i18n.getString('add_more')" onclick='generateTemplateMessageForm();'>
+			</td>
+		</tr>
+	</table>
+	#end
+	
   <table>
 	 <tr>
       	<td colspan='3'>
@@ -186,4 +277,20 @@
 		</td>
       </tr>
   </table>
-</form>	
+</form>
+
+<script>
+	var i18n_reminder = '$encoder.jsEscape( $i18n.getString( "reminder" ) , "'")';   
+	var i18n_remove_reminder = '$encoder.jsEscape( $i18n.getString( "remove_reminder" ) , "'")';   
+	var i18n_days_before_after_enrollment_date = '$encoder.jsEscape( $i18n.getString( "days_before_after_enrollment_date" ) , "'")';   
+	var i18n_params = '$encoder.jsEscape( $i18n.getString( "params" ) , "'")';   
+	var i18n_patient_name = '$encoder.jsEscape( $i18n.getString( "patient_name" ) , "'")';   
+	var i18n_program_name = '$encoder.jsEscape( $i18n.getString( "program_name" ) , "'")';   
+	var i18n_incident_date = '$encoder.jsEscape( $i18n.getString( "incident_date" ) , "'")';   
+	var i18n_days_since_incident_date = '$encoder.jsEscape( $i18n.getString( "days_since_incident_date" ) , "'")';   
+	var i18n_orgunit_name = '$encoder.jsEscape( $i18n.getString( "orgunit_name" ) , "'")';   
+	var i18n_enrollement_date = '$encoder.jsEscape( $i18n.getString( "enrollement_date" ) , "'")';   
+	var i18n_days_since_enrollment_date = '$encoder.jsEscape( $i18n.getString( "days_since_enrollment_date" ) , "'")';   
+	var i18n_message = '$encoder.jsEscape( $i18n.getString( "message" ) , "'")';   
+	var i18n_name_exists = '$encoder.jsEscape( $i18n.getString( "name_exists" ) , "'")';   
+</script>