← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 8026: Automatic SMS reminder (WIP).

 

------------------------------------------------------------
revno: 8026
committer: Tran Chau <tran.hispvietnam@xxxxxxxxx>
branch nick: dhis2
timestamp: Mon 2012-09-10 17:28:33 +0700
message:
  Automatic SMS reminder (WIP).
added:
  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/
  dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/patient/scheduling/DefaultProgramSchedulingManager.java
  dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/patient/scheduling/ProgramSchedulingManager.java
  dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/patient/scheduling/SendScheduledMessageTask.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/schedule/
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/schedule/GetGatewayAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/schedule/ScheduleSendMessageTasksAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/javascript/scheduling.js
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/jsonResponseScheduleTasks.vm
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/menuScheduling.vm
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/scheduleSendMessage.vm
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramStageInstanceService.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramStageInstanceStore.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/setting/SystemSettingManager.java
  dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/DefaultProgramStageInstanceService.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-reporting/src/main/java/org/hisp/dhis/scheduling/SchedulingManager.java
  dhis-2/dhis-web/dhis-web-caseentry/src/main/java/org/hisp/dhis/caseentry/action/reminder/SendSmsToListAction.java
  dhis-2/dhis-web/dhis-web-caseentry/src/main/webapp/dhis-web-caseentry/patientProgramTracking.vm
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/pom.xml
  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/resources/struts.xml
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/index.vm
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/menu.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/program/ProgramStageInstanceService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramStageInstanceService.java	2012-08-16 13:46:23 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramStageInstanceService.java	2012-09-10 10:28:33 +0000
@@ -99,4 +99,6 @@
     void removeEmptyEvents( ProgramStage programStage );
 
     void updateProgramStageInstances( Collection<Integer> programStageInstances, OutboundSms outboundSms );
+    
+    Collection<SchedulingProgramObject> getSendMesssageEvents();
 }

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramStageInstanceStore.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramStageInstanceStore.java	2012-08-16 13:46:23 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramStageInstanceStore.java	2012-09-10 10:28:33 +0000
@@ -85,4 +85,6 @@
     void removeEmptyEvents( ProgramStage programStage );
 
     void update( Collection<Integer> programStageInstanceIds, OutboundSms outboundSms );
+    
+    Collection<SchedulingProgramObject> getSendMesssageEvents();
 }

=== added 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	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/SchedulingProgramObject.java	2012-09-10 10:28:33 +0000
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2004-2009, 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;
+
+/**
+ * @author Chau Thu Tran
+ * 
+ * @version SchedulingProgramObject.java 4:45:18 PM Sep 10, 2012 $
+ */
+public class SchedulingProgramObject
+{
+    private String phoneNumber;
+
+    private ProgramStageInstance programStageInstance;
+
+    private String message;
+
+    public SchedulingProgramObject()
+    {
+
+    }
+
+    public SchedulingProgramObject( String phonenumber, ProgramStageInstance programStageInstance, String message )
+    {
+        this.phoneNumber = phonenumber;
+        this.programStageInstance = programStageInstance;
+        this.message = message;
+    }
+
+    public String getPhoneNumber()
+    {
+        return phoneNumber;
+    }
+
+    public void setPhoneNumber( String phoneNumber )
+    {
+        this.phoneNumber = phoneNumber;
+    }
+
+    public ProgramStageInstance getProgramStageInstance()
+    {
+        return programStageInstance;
+    }
+
+    public void setProgramStageInstance( ProgramStageInstance programStageInstance )
+    {
+        this.programStageInstance = programStageInstance;
+    }
+
+    public String getMessage()
+    {
+        return message;
+    }
+
+    public void setMessage( String message )
+    {
+        this.message = message;
+    }
+
+}

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/setting/SystemSettingManager.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/setting/SystemSettingManager.java	2012-09-10 03:17:24 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/setting/SystemSettingManager.java	2012-09-10 10:28:33 +0000
@@ -70,6 +70,8 @@
     final String KEY_SMS_CONFIG = "SMS_CONFIG";
     final String KEY_CACHE_STRATEGY = "keyCacheStrategy";
     final String KEY_TIME_FOR_SENDING_MESSAGE = "timeSendingMessage";
+    final String KEY_SEND_MESSAGE_SCHEDULED_TASKS = "sendMessageScheduled";
+    final String KEY_SEND_MESSAGE_GATEWAY = "keySendMessageGateway";
 
     final int DEFAULT_MAX_NUMBER_OF_ATTEMPTS = 20;
     final int DEFAULT_TIMEFRAME_MINUTES = 1;

=== added directory 'dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/patient/scheduling'
=== added file 'dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/patient/scheduling/DefaultProgramSchedulingManager.java'
--- dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/patient/scheduling/DefaultProgramSchedulingManager.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/patient/scheduling/DefaultProgramSchedulingManager.java	2012-09-10 10:28:33 +0000
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2004-2009, 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.patient.scheduling;
+
+import static org.hisp.dhis.setting.SystemSettingManager.KEY_SEND_MESSAGE_SCHEDULED_TASKS;
+import static org.hisp.dhis.system.scheduling.Scheduler.STATUS_NOT_STARTED;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hisp.dhis.setting.SystemSettingManager;
+import org.hisp.dhis.system.scheduling.Scheduler;
+
+/**
+ * @author Chau Thu Tran
+ *
+ * @version DefaultProgramSchedulingManager.java 12:51:02 PM Sep 10, 2012 $
+ */
+public class DefaultProgramSchedulingManager implements ProgramSchedulingManager
+{
+
+    // -------------------------------------------------------------------------
+    // Dependencies
+    // -------------------------------------------------------------------------
+
+    private SystemSettingManager systemSettingManager;
+    
+    public void setSystemSettingManager( SystemSettingManager systemSettingManager )
+    {
+        this.systemSettingManager = systemSettingManager;
+    }
+
+    private Scheduler scheduler;
+
+    public void setScheduler( Scheduler scheduler )
+    {
+        this.scheduler = scheduler;
+    }
+
+    private Map<String, Runnable> tasks = new HashMap<String, Runnable>();
+
+    public void setTasks( Map<String, Runnable> tasks )
+    {
+        this.tasks = tasks;
+    }
+
+    // -------------------------------------------------------------------------
+    // SchedulingManager implementation
+    // -------------------------------------------------------------------------
+
+    public void scheduleTasks()
+    {
+        Map<String, String> keyCronMap = getScheduledTasks();
+        
+        for ( String key : keyCronMap.keySet() )
+        {
+            String cron = keyCronMap.get( key );
+            Runnable task = tasks.get( key );
+            
+            if ( cron != null && task != null )
+            {
+                scheduler.scheduleTask( key, task, cron );
+            }
+        }
+    }
+    
+    public void scheduleTasks( Map<String, String> keyCronMap )
+    {
+        systemSettingManager.saveSystemSetting( KEY_SEND_MESSAGE_SCHEDULED_TASKS, new HashMap<String, String>( keyCronMap ) );
+        
+        scheduleTasks();
+    }
+    
+    public void stopTasks()
+    {
+        systemSettingManager.saveSystemSetting( KEY_SEND_MESSAGE_SCHEDULED_TASKS, null );
+        
+        scheduler.stopAllTasks();
+    }
+    
+    public void executeTasks()
+    {
+        Map<String, String> keyCronMap = getScheduledTasks();
+        
+        for ( String key : keyCronMap.keySet() )
+        {
+            Runnable task = tasks.get( key );
+            
+            if ( task != null )
+            {
+                scheduler.executeTask( task );
+            }
+        }
+    }
+    
+    @SuppressWarnings("unchecked")
+    public Map<String, String> getScheduledTasks()
+    {
+        return (Map<String, String>) systemSettingManager.getSystemSetting( KEY_SEND_MESSAGE_SCHEDULED_TASKS, new HashMap<String, String>() );
+    }
+    
+    public String getTaskStatus()
+    {
+        Map<String, String> keyCronMap = getScheduledTasks();
+                
+        if ( keyCronMap.size() == 0 )
+        {
+            return STATUS_NOT_STARTED;
+        }
+        
+        return scheduler.getTaskStatus( keyCronMap.keySet().iterator().next() );
+    }
+}
+

=== added file 'dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/patient/scheduling/ProgramSchedulingManager.java'
--- dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/patient/scheduling/ProgramSchedulingManager.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/patient/scheduling/ProgramSchedulingManager.java	2012-09-10 10:28:33 +0000
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2004-2009, 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.patient.scheduling;
+
+import java.util.Map;
+
+/**
+ * @author Chau Thu Tran
+ *
+ * @version ProgramSchedulingManager.java 12:47:57 PM Sep 10, 2012 $
+ */
+public interface ProgramSchedulingManager
+{
+    final String TASK_SENDING_MESSAGE = "sendingMessageTask";
+    
+    void scheduleTasks();
+    
+    void scheduleTasks( Map<String, String> keyCronMap );
+    
+    void stopTasks();
+    
+    void executeTasks();
+    
+    Map<String, String> getScheduledTasks();
+    
+    String getTaskStatus();   
+}

=== added 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	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/patient/scheduling/SendScheduledMessageTask.java	2012-09-10 10:28:33 +0000
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2004-2009, 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.patient.scheduling;
+
+import static org.hisp.dhis.setting.SystemSettingManager.KEY_SEND_MESSAGE_GATEWAY;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.hisp.dhis.program.ProgramStageInstance;
+import org.hisp.dhis.program.ProgramStageInstanceService;
+import org.hisp.dhis.program.SchedulingProgramObject;
+import org.hisp.dhis.setting.SystemSettingManager;
+import org.hisp.dhis.sms.SmsServiceException;
+import org.hisp.dhis.sms.outbound.OutboundSms;
+import org.hisp.dhis.sms.outbound.OutboundSmsService;
+
+/**
+ * @author Chau Thu Tran
+ * 
+ * @version SendScheduledMessageTask.java 12:57:53 PM Sep 10, 2012 $
+ */
+public class SendScheduledMessageTask
+    implements Runnable
+{
+    private SystemSettingManager systemSettingManager;
+
+    public void setSystemSettingManager( SystemSettingManager systemSettingManager )
+    {
+        this.systemSettingManager = systemSettingManager;
+    }
+
+    private ProgramStageInstanceService programStageInstanceService;
+
+    public void setProgramStageInstanceService( ProgramStageInstanceService programStageInstanceService )
+    {
+        this.programStageInstanceService = programStageInstanceService;
+    }
+
+    private OutboundSmsService outboundSmsService;
+
+    public void setOutboundSmsService( OutboundSmsService outboundSmsService )
+    {
+        this.outboundSmsService = outboundSmsService;
+    }
+
+    // -------------------------------------------------------------------------
+    // Constructors
+    // -------------------------------------------------------------------------
+
+    public SendScheduledMessageTask()
+    {
+    }
+    
+    public SendScheduledMessageTask( SystemSettingManager systemSettingManager,
+        ProgramStageInstanceService programStageInstanceService, OutboundSmsService outboundSmsService )
+    {
+        this.systemSettingManager = systemSettingManager;
+        this.programStageInstanceService = programStageInstanceService;
+        this.outboundSmsService = outboundSmsService;
+    }
+
+    // -------------------------------------------------------------------------
+    // Runnable implementation
+    // -------------------------------------------------------------------------
+
+    @Override
+    public void run()
+    {
+        String gatewayId = (String) systemSettingManager.getSystemSetting( KEY_SEND_MESSAGE_GATEWAY );
+
+        if ( gatewayId != null )
+        {
+            Collection<SchedulingProgramObject> schedulingProgramObjects = programStageInstanceService
+                .getSendMesssageEvents();
+
+            for ( SchedulingProgramObject schedulingProgramObject : schedulingProgramObjects )
+            {
+                String message = schedulingProgramObject.getMessage();
+                 
+                String phoneNumber = schedulingProgramObject.getPhoneNumber();
+                
+                ProgramStageInstance programStageInstance = schedulingProgramObject.getProgramStageInstance();
+                
+                if ( phoneNumber != null && !phoneNumber.isEmpty() )
+                {
+                    try
+                    {
+                        OutboundSms outboundSms = new OutboundSms( message, phoneNumber );
+                        outboundSmsService.sendMessage( outboundSms, gatewayId );
+
+//                        List<OutboundSms> outboundSmsList = programStageInstance.getOutboundSms();
+//                        if ( outboundSmsList == null )
+//                        {
+//                            outboundSmsList = new ArrayList<OutboundSms>();
+//                        }
+//                        outboundSmsList.add( outboundSms );
+//                        programStageInstance.setOutboundSms( outboundSmsList );
+//                        programStageInstanceService.updateProgramStageInstance( programStageInstance );
+                    }
+                    catch ( SmsServiceException e )
+                    {
+                        message = e.getMessage();
+                    }
+                }
+            }
+        }
+    }
+}

=== modified file 'dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/DefaultProgramStageInstanceService.java'
--- dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/DefaultProgramStageInstanceService.java	2012-09-07 07:57:47 +0000
+++ dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/DefaultProgramStageInstanceService.java	2012-09-10 10:28:33 +0000
@@ -27,7 +27,6 @@
 package org.hisp.dhis.program;
 
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.Collection;
 import java.util.Date;
 import java.util.HashMap;
@@ -269,4 +268,9 @@
     {
         programStageInstanceStore.update( programStageInstanceIds, outboundSms );
     }
+
+    public Collection<SchedulingProgramObject> getSendMesssageEvents()
+    {
+        return programStageInstanceStore.getSendMesssageEvents();
+    }
 }

=== 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	2012-08-16 13:46:23 +0000
+++ dhis-2/dhis-services/dhis-service-patient/src/main/java/org/hisp/dhis/program/hibernate/HibernateProgramStageInstanceStore.java	2012-09-10 10:28:33 +0000
@@ -29,6 +29,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 
@@ -47,6 +48,7 @@
 import org.hisp.dhis.program.ProgramStage;
 import org.hisp.dhis.program.ProgramStageInstance;
 import org.hisp.dhis.program.ProgramStageInstanceStore;
+import org.hisp.dhis.program.SchedulingProgramObject;
 import org.hisp.dhis.sms.outbound.OutboundSms;
 import org.hisp.dhis.system.grid.GridUtils;
 import org.hisp.dhis.system.grid.ListGrid;
@@ -253,14 +255,14 @@
             if ( programStageInstanceId != null && programStageInstanceId != 0 )
             {
                 ProgramStageInstance programStageInstance = get( programStageInstanceId );
-                
+
                 List<OutboundSms> outboundSmsList = programStageInstance.getOutboundSms();
-                
-                if( outboundSmsList == null)
+
+                if ( outboundSmsList == null )
                 {
                     outboundSmsList = new ArrayList<OutboundSms>();
                 }
-                
+
                 outboundSmsList.add( outboundSms );
                 programStageInstance.setOutboundSms( outboundSmsList );
                 update( programStageInstance );
@@ -268,6 +270,77 @@
         }
     }
 
+    public Collection<SchedulingProgramObject> getSendMesssageEvents()
+    {
+        String sql = "select psi.programstageinstanceid, p.phonenumber, ps.templatemessage, p.firstname, org.name as orgunitName "
+            + " ,pg.name as programName, ps.name as programStageName, psi.duedate,(DATE(now()) - DATE(psi.duedate) ) as days_since_due_date "
+            + " ,psi.duedate "
+            + " from patient p INNER JOIN programinstance pi " 
+            + "         ON p.patientid=pi.patientid "
+            + " INNER JOIN programstageinstance psi " 
+            + "         ON psi.programinstanceid=pi.programinstanceid "
+            + " INNER JOIN program pg " 
+            + "         ON pg.programid=pi.programid " + " INNER JOIN programstage ps "
+            + "         ON ps.programstageid=psi.programstageid "
+            + " INNER JOIN organisationunit org "
+            + "         ON org.organisationunitid = p.organisationunitid "
+            + " WHERE pi.completed=false and psi.completed=false "
+            + "         and p.phonenumber is not NULL and p.phonenumber != '' "
+            + "         and ps.templatemessage is not NULL and ps.templatemessage != '' "
+            + "         and pg.type=1 and ps.daysallowedsendmessage is not null "
+            + "         and (DATE(now()) - DATE(psi.duedate) ) = ps.daysallowedsendmessage ";
+
+        SqlRowSet rs = jdbcTemplate.queryForRowSet( sql );
+
+        int cols = rs.getMetaData().getColumnCount();
+
+        Collection<SchedulingProgramObject> schedulingProgramObjects = new HashSet<SchedulingProgramObject>();
+
+        while ( rs.next() )
+        {
+          
+            for ( int i = 1; i <= cols; i++ )
+            {
+                 
+                String message = rs.getString( "templatemessage" );
+                String patientName = rs.getString( "firstName" );
+                String organisationunitName = rs.getString( "orgunitName" );
+                String programName = rs.getString( "programName" );
+                String programStageName = rs.getString( "programStageName" );
+                String days_since_due_date = rs.getString( "days_since_due_date" );
+                String dueDate = rs.getString( "duedate" );
+                
+                message.replaceAll( ProgramStage.TEMPLATE_MESSSAGE_PATIENT_NAME, patientName );
+                message.replaceAll( ProgramStage.TEMPLATE_MESSSAGE_PROGRAM_NAME, programName );
+                message.replaceAll( ProgramStage.TEMPLATE_MESSSAGE_PROGAM_STAGE_NAME, programStageName );
+                message.replaceAll( ProgramStage.TEMPLATE_MESSSAGE_DUE_DATE, dueDate );
+                message.replaceAll( ProgramStage.TEMPLATE_MESSSAGE_ORGUNIT_NAME, organisationunitName );
+                message.replaceAll( ProgramStage.TEMPLATE_MESSSAGE_DAYS_SINCE_DUE_DATE, dueDate );
+                
+                SchedulingProgramObject schedulingProgramObject = new SchedulingProgramObject();
+                schedulingProgramObject.setProgramStageInstance( get(rs.getInt( "programstageinstanceid" )) );
+                schedulingProgramObject.setPhoneNumber( rs.getString( "phonenumber" ) );
+                schedulingProgramObject.setMessage( message );
+                
+                schedulingProgramObjects.add(schedulingProgramObject);
+               
+            }
+        }
+
+        /*
+         * Collection<ProgramStageInstance> programStageInstances = new
+         * HashSet<ProgramStageInstance>();
+         * 
+         * try { programStageInstances = jdbcTemplate.query( sql, new
+         * RowMapper<ProgramStageInstance>() { public ProgramStageInstance
+         * mapRow( ResultSet rs, int rowNum ) throws SQLException { return
+         * get(rs.getInt( "programstageinstanceid" )); } } ); } catch (
+         * Exception ex ) { ex.printStackTrace(); }
+         */
+
+        return schedulingProgramObjects;
+    }
+
     // -------------------------------------------------------------------------
     // Supportive methods
     // -------------------------------------------------------------------------

=== 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	2012-09-04 10:10:05 +0000
+++ dhis-2/dhis-services/dhis-service-patient/src/main/resources/META-INF/dhis/beans.xml	2012-09-10 10:28:33 +0000
@@ -388,7 +388,29 @@
 		<property name="sessionFactory" ref="sessionFactory" />
 	</bean>
 	
-	<!-- Startup -->
+	<!-- Scheduling -->
+	
+	<bean id="org.hisp.dhis.patient.scheduling.ProgramSchedulingManager" class="org.hisp.dhis.patient.scheduling.DefaultProgramSchedulingManager"
+   	 init-method="scheduleTasks">
+    <property name="systemSettingManager" ref="org.hisp.dhis.setting.SystemSettingManager" />
+    <property name="scheduler" ref="scheduler" />
+    <property name="tasks">
+      <map>
+        <entry key="sendMessageScheduled" value-ref="sendMessageScheduled" />
+      </map>
+    </property>
+   </bean>
+  
+ 	<bean id="sendMessageScheduledTasks" class="org.hisp.dhis.patient.scheduling.SendScheduledMessageTask" >
+ 		<constructor-arg ref="org.hisp.dhis.program.ProgramStageInstanceService" />
+ 		<constructor-arg ref="org.hisp.dhis.setting.SystemSettingManager" />
+ 		<constructor-arg ref="org.hisp.dhis.sms.outbound.OutboundSmsService" />
+ 	</bean>
+ 	
+ 	<bean id="sendMessageScheduled" class="org.hisp.dhis.patient.scheduling.SendScheduledMessageTask" parent="sendMessageScheduledTasks">
+	</bean>  
+  	
+    <!-- Startup -->
 
 	<bean id="org.hisp.dhis.patient.startup.TableAlteror" class="org.hisp.dhis.patient.startup.TableAlteror">
 		<property name="statementManager" ref="statementManager" />

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/scheduling/SchedulingManager.java'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/scheduling/SchedulingManager.java	2012-07-24 07:11:35 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/scheduling/SchedulingManager.java	2012-09-10 10:28:33 +0000
@@ -37,7 +37,7 @@
     final String TASK_DATAMART_LAST_12_MONTHS = "dataMartLast12MonthsTask";
     final String TASK_DATAMART_LAST_6_MONTS = "dataMartLast6MonthsTask";
     final String TASK_DATAMART_FROM_6_TO_12_MONTS = "dataMartFrom6To12MonthsTask";
-    
+        
     void scheduleTasks();
     
     void scheduleTasks( Map<String, String> keyCronMap );

=== modified file 'dhis-2/dhis-web/dhis-web-caseentry/src/main/java/org/hisp/dhis/caseentry/action/reminder/SendSmsToListAction.java'
--- dhis-2/dhis-web/dhis-web-caseentry/src/main/java/org/hisp/dhis/caseentry/action/reminder/SendSmsToListAction.java	2012-08-16 13:46:23 +0000
+++ dhis-2/dhis-web/dhis-web-caseentry/src/main/java/org/hisp/dhis/caseentry/action/reminder/SendSmsToListAction.java	2012-09-10 10:28:33 +0000
@@ -174,16 +174,4 @@
         return SUCCESS;
     }
     
-//    private String convertPhoneNumberList( Collection<String> phoneNumberList )
-//    {
-//        String result = "";
-//        
-//        for( String phoneNumber : phoneNumberList )
-//        {
-//            result = phoneNumber + ";";
-//        }
-//        
-//        return result;
-//    }
-
 }

=== modified file 'dhis-2/dhis-web/dhis-web-caseentry/src/main/webapp/dhis-web-caseentry/patientProgramTracking.vm'
--- dhis-2/dhis-web/dhis-web-caseentry/src/main/webapp/dhis-web-caseentry/patientProgramTracking.vm	2012-09-07 07:57:47 +0000
+++ dhis-2/dhis-web/dhis-web-caseentry/src/main/webapp/dhis-web-caseentry/patientProgramTracking.vm	2012-09-10 10:28:33 +0000
@@ -140,7 +140,7 @@
 					</td>
 					<td>
 						<a href="javascript:setFieldValue('sendToList', false);showSendSmsForm('$programStageInstance.programStage.name',$programStageInstance.id)" title='$i18n.getString( "send_sms" )'><img src="images/sms.png" alt='$i18n.getString( "send_sms" )'></a>
-						#if($programStageInstance.irregular!='true')
+						#if($programStageInstance.irregular=='true')
 							<a href="javascript:removeEvent($programStageInstance.id)" title='$i18n.getString( "remove" )'><img src="../images/delete.png" alt='$i18n.getString( "remove" )'></a>
 						#end
 					</td>

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/pom.xml'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/pom.xml	2012-08-22 13:07:24 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/pom.xml	2012-09-10 10:28:33 +0000
@@ -38,6 +38,10 @@
       <groupId>org.hisp.dhis</groupId>
       <artifactId>dhis-service-core</artifactId>  
     </dependency>
+	<dependency>
+      <groupId>org.hisp.dhis</groupId>
+      <artifactId>dhis-service-sms</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.hisp.dhis</groupId>
       <artifactId>dhis-web-commons</artifactId>

=== added directory 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/schedule'
=== added file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/schedule/GetGatewayAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/schedule/GetGatewayAction.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/schedule/GetGatewayAction.java	2012-09-10 10:28:33 +0000
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2004-2009, 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.patient.action.schedule;
+
+import java.util.Map;
+
+import org.hisp.dhis.patient.scheduling.ProgramSchedulingManager;
+import org.hisp.dhis.sms.outbound.OutboundSmsTransportService;
+import org.hisp.dhis.system.scheduling.Scheduler;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.opensymphony.xwork2.Action;
+
+/**
+ * @author Chau Thu Tran
+ * 
+ * @version GetGatewayAction.java 10:57:08 AM Aug 9, 2012 $
+ */
+public class GetGatewayAction
+    implements Action
+{
+    // -------------------------------------------------------------------------
+    // Dependencies
+    // -------------------------------------------------------------------------
+
+    @Autowired
+    private OutboundSmsTransportService transportService;
+
+    private ProgramSchedulingManager schedulingManager;
+
+    public void setSchedulingManager( ProgramSchedulingManager schedulingManager )
+    {
+        this.schedulingManager = schedulingManager;
+    }
+
+    // -------------------------------------------------------------------------
+    // Input/Output
+    // -------------------------------------------------------------------------
+
+    public Map<String, String> gatewayMap;
+
+    public Map<String, String> getGatewayMap()
+    {
+        return gatewayMap;
+    }
+
+    private String status;
+
+    public String getStatus()
+    {
+        return status;
+    }
+
+    private boolean running;
+
+    public boolean isRunning()
+    {
+        return running;
+    }
+
+    // -------------------------------------------------------------------------
+    // Action implementation
+    // -------------------------------------------------------------------------
+
+    @Override
+    public String execute()
+        throws Exception
+    {
+        gatewayMap = transportService.getGatewayMap();
+
+        status = schedulingManager.getTaskStatus();
+        running = Scheduler.STATUS_RUNNING.equals( status );
+
+        return SUCCESS;
+    }
+
+}

=== added file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/schedule/ScheduleSendMessageTasksAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/schedule/ScheduleSendMessageTasksAction.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/java/org/hisp/dhis/patient/action/schedule/ScheduleSendMessageTasksAction.java	2012-09-10 10:28:33 +0000
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2004-2009, 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.patient.action.schedule;
+
+import static org.hisp.dhis.setting.SystemSettingManager.DEFAULT_TIME_FOR_SENDING_MESSAGE;
+import static org.hisp.dhis.setting.SystemSettingManager.KEY_SEND_MESSAGE_GATEWAY;
+import static org.hisp.dhis.setting.SystemSettingManager.KEY_TIME_FOR_SENDING_MESSAGE;
+import static org.hisp.dhis.setting.SystemSettingManager.KEY_SEND_MESSAGE_SCHEDULED_TASKS;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hisp.dhis.patient.scheduling.ProgramSchedulingManager;
+import org.hisp.dhis.setting.SystemSettingManager;
+import org.hisp.dhis.system.scheduling.Scheduler;
+
+import com.opensymphony.xwork2.Action;
+
+/**
+ * @author Chau Thu Tran
+ * 
+ * @version ScheduleSendMessageTasksAction.java 12:10:35 PM Sep 10, 2012 $
+ */
+public class ScheduleSendMessageTasksAction
+    implements Action
+{
+    // -------------------------------------------------------------------------
+    // Dependencies
+    // -------------------------------------------------------------------------
+
+    private SystemSettingManager systemSettingManager;
+
+    public void setSystemSettingManager( SystemSettingManager systemSettingManager )
+    {
+        this.systemSettingManager = systemSettingManager;
+    }
+
+    private ProgramSchedulingManager schedulingManager;
+
+    public void setSchedulingManager( ProgramSchedulingManager schedulingManager )
+    {
+        this.schedulingManager = schedulingManager;
+    }
+
+    // -------------------------------------------------------------------------
+    // Input
+    // -------------------------------------------------------------------------
+
+    private boolean execute;
+
+    public void setExecute( boolean execute )
+    {
+        this.execute = execute;
+    }
+
+    private boolean schedule;
+
+    public void setSchedule( boolean schedule )
+    {
+        this.schedule = schedule;
+    }
+
+    private String gateWayId;
+
+    public void setGateWayId( String gateWayId )
+    {
+        this.gateWayId = gateWayId;
+    }
+
+    // -------------------------------------------------------------------------
+    // Output
+    // -------------------------------------------------------------------------
+
+    private String status;
+
+    public String getStatus()
+    {
+        return status;
+    }
+
+    private boolean running;
+
+    public boolean isRunning()
+    {
+        return running;
+    }
+
+    // -------------------------------------------------------------------------
+    // Action implementation
+    // -------------------------------------------------------------------------
+
+    public String execute()
+    {
+        systemSettingManager.saveSystemSetting( KEY_SEND_MESSAGE_GATEWAY, gateWayId );
+
+        if ( execute )
+        {
+            schedulingManager.executeTasks();
+        }
+        else if ( schedule )
+        {
+            if ( Scheduler.STATUS_RUNNING.equals( schedulingManager.getTaskStatus() ) )
+            {
+                schedulingManager.stopTasks();
+            }
+            else
+            {
+                Map<String, String> keyCronMap = new HashMap<String, String>();
+                String time = (String) systemSettingManager.getSystemSetting( KEY_TIME_FOR_SENDING_MESSAGE,
+                    DEFAULT_TIME_FOR_SENDING_MESSAGE );
+
+                String[] infor = time.split( ":" );
+
+                String hour = infor[0].trim();
+                String minute = infor[1].trim();
+
+                if ( hour.trim().equals( "00" ) )
+                {
+                    hour = "0";
+                }
+
+                if ( minute.trim().equals( "00" ) )
+                {
+                    minute = "0";
+                }
+
+                String cron = "0 " + Integer.parseInt(minute) + " " + Integer.parseInt( hour ) + " ? * *";
+
+                keyCronMap.put( KEY_SEND_MESSAGE_SCHEDULED_TASKS, cron );
+
+                schedulingManager.scheduleTasks( keyCronMap );
+            }
+        }
+
+        status = schedulingManager.getTaskStatus();
+        running = Scheduler.STATUS_RUNNING.equals( status );
+
+        return SUCCESS;
+    }
+}

=== 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	2012-09-05 14:30:23 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/resources/META-INF/dhis/beans.xml	2012-09-10 10:28:33 +0000
@@ -880,5 +880,18 @@
 			<ref bean="org.hisp.dhis.program.ProgramValidationService" />
 		</property>
 	</bean>
+	
+	<!-- Scheduling -->
+	
+	<bean id="org.hisp.dhis.patient.action.schedule.GetGatewayAction"
+		class="org.hisp.dhis.patient.action.schedule.GetGatewayAction"
+		scope="prototype">
+		<property name="schedulingManager" ref="org.hisp.dhis.patient.scheduling.ProgramSchedulingManager" />
+	</bean>
+	
+	<bean id="org.hisp.dhis.patient.action.schedule.ScheduleSendMessageTasksAction" class="org.hisp.dhis.patient.action.schedule.ScheduleSendMessageTasksAction"  scope="prototype">
+ 		 <property name="systemSettingManager" ref="org.hisp.dhis.setting.SystemSettingManager" />
+ 		 <property name="schedulingManager" ref="org.hisp.dhis.patient.scheduling.ProgramSchedulingManager" />
+ 	</bean>
 
 </beans>
\ No newline at end of file

=== 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	2012-09-10 02:46:35 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/resources/org/hisp/dhis/patient/i18n_module.properties	2012-09-10 10:28:33 +0000
@@ -277,4 +277,15 @@
 program_stage_name = Program stage name
 due_date = Due date
 orgunit_name = Organisation unit name
-days_since_due_date = Days since due date
\ No newline at end of file
+days_since_due_date = Days since due date
+scheduling = Scheduling
+schedule_sending_message = Schedule sending message
+schedule = Schedule
+start = Start
+stop = Stop
+schedule_sending_message = Schedule sending message
+scheduling_is = Scheduling is
+not_started = not started
+running = running
+gateway_type = Gateway type
+execute = Execute
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/resources/struts.xml'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/resources/struts.xml	2012-09-05 14:30:23 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/resources/struts.xml	2012-09-10 10:28:33 +0000
@@ -927,5 +927,22 @@
 			<param name="onExceptionReturn">plainTextError</param>
 		</action>
 		
+		<!-- Scheduling -->
+		
+		<action name="viewScheduleTasks" class="org.hisp.dhis.patient.action.schedule.GetGatewayAction">
+	      <result name="success" type="velocity">/main.vm</result>
+	      <param name="page">/dhis-web-maintenance-patient/scheduleSendMessage.vm</param>
+	      <param name="menu">/dhis-web-maintenance-patient/menu.vm</param>
+	      <param name="javascripts">javascript/scheduling.js</param>
+		  <param name="schedule">true</param>
+	      <param name="requiredAuthorities">F_SCHEDULING_ADMIN</param>
+	    </action>
+	    
+		<action name="scheduleTasks" class="org.hisp.dhis.patient.action.schedule.ScheduleSendMessageTasksAction">
+	      <result name="success" type="velocity-json">
+				/dhis-web-maintenance-patient/jsonResponseScheduleTasks.vm</result>
+	      <param name="requiredAuthorities">F_SCHEDULING_SEND_MESSAGE</param>
+	    </action>
+		
 	</package>
 </struts>

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/index.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/index.vm	2012-07-04 05:06:10 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/index.vm	2012-09-10 10:28:33 +0000
@@ -15,4 +15,5 @@
     #introListImgItem( "program.action" "program" "program" )
     #introListImgItem( "caseAggregation.action" "patient_aggregation_query_builder" "caseaggregationmapping" )
 	#introListImgItem( "validationCriteria.action" "validation_criteria" "validationcriteria" )
+	#introListImgItem( "viewScheduleTasks.action" "schedule_sending_message" "validationcriteria" )
 </ul>
\ No newline at end of file

=== added file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/javascript/scheduling.js'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/javascript/scheduling.js	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/javascript/scheduling.js	2012-09-10 10:28:33 +0000
@@ -0,0 +1,25 @@
+function scheduleTasks()
+{
+	$.post( 'scheduleTasks.action',{
+		execute:false,
+		schedule: true,
+		gateWayId: getFieldValue("gatewayId")
+	}, function( json ){
+		setMessage(i18n_scheduling_is + " " + json.scheduleTasks.status);
+		if( json.scheduleTasks.running ){
+			setFieldValue('scheduledBtn', i18n_stop );
+		}
+		else{
+			setFieldValue('scheduledBtn', i18n_start );
+		}
+	});
+}
+
+function executeTasks()
+{
+	$.post( 'scheduleTasks.action',{
+		execute:true,
+		schedule: false,
+		gateWayId: getFieldValue("gatewayId")
+	});
+}

=== added file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/jsonResponseScheduleTasks.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/jsonResponseScheduleTasks.vm	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/jsonResponseScheduleTasks.vm	2012-09-10 10:28:33 +0000
@@ -0,0 +1,6 @@
+{ "scheduleTasks":
+  {
+    "status": "$status",
+	"running": "$running"
+  }
+}
\ 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/menu.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/menu.vm	2012-05-24 05:13:57 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/menu.vm	2012-09-10 10:28:33 +0000
@@ -12,3 +12,9 @@
 	<li><a href="caseAggregation.action">$i18n.getString( "aggregation_query_builder" )</a></li>
 	<li><a href="validationCriteria.action">$i18n.getString( "validation_criteria" )</a></li>
 </ul>
+
+<h2>$i18n.getString( "scheduling" )</h2>
+<ul>
+	<li><a href="viewScheduleTasks.action">$i18n.getString( "schedule_sending_message" )</a></li>
+</ul>
+

=== added file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/menuScheduling.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/menuScheduling.vm	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/menuScheduling.vm	2012-09-10 10:28:33 +0000
@@ -0,0 +1,14 @@
+<h2>$i18n.getString( "patients" )</h2>
+<ul>
+	<li><a href="patientAttribute.action">$i18n.getString( "patient_attribute" )</a></li>
+	<li><a href="patientAttributeGroup.action">$i18n.getString( "patient_attribute_group" )</a></li>
+	<li><a href="patientIdentifierType.action">$i18n.getString( "patient_identifier_type" )</a></li>
+	<li><a href="relationshipType.action">$i18n.getString( "relationship_type" )</a></li>
+</ul>
+
+<h2>$i18n.getString( "programs" )</h2>
+<ul>
+	<li><a href="program.action">$i18n.getString( "program" )</a></li>
+	<li><a href="caseAggregation.action">$i18n.getString( "aggregation_query_builder" )</a></li>
+	<li><a href="validationCriteria.action">$i18n.getString( "validation_criteria" )</a></li>
+</ul>

=== added file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/scheduleSendMessage.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/scheduleSendMessage.vm	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-patient/src/main/webapp/dhis-web-maintenance-patient/scheduleSendMessage.vm	2012-09-10 10:28:33 +0000
@@ -0,0 +1,39 @@
+<h3>$i18n.getString('schedule_sending_message')</h3>
+<table>
+	<tbody>
+		<tr>
+			<td>$i18n.getString( "gateway_type" )</td>
+			<td>
+				#set( $keys = $!gatewayMap.keySet() )
+				<select id="gatewayId" name="gatewayId" style="width:300px;">
+					#foreach( $key in $!keys )
+					<option value="$gatewayMap.get( $key )" >$i18n.getString( $key )</option>
+					#end
+				</select>
+			</td>
+		</tr>
+		
+		<tr>
+			<td></td>
+			<td>
+				<input type="button" style="width:150px;" id="scheduledBtn" name="scheduledBtn"
+				#if ( $running )
+					value="$i18n.getString( 'stop' )"
+				#else
+					value="$i18n.getString( 'start' )"
+				#end
+				onclick="scheduleTasks();"/>
+				<input type="button" style="width:150px;" value="$i18n.getString( 'execute' )" onclick="executeTasks();"/>
+			</td>
+		</tr>
+		
+	</tbody>
+</table>
+<span id='message' style="display:block;">$i18n.getString( "scheduling_is" ) $!i18n.getString( $!status )</span>
+
+<script>
+	var i18n_scheduled = '$encoder.jsEscape( $i18n.getString( "run_success" ) , "'" )';
+	var i18n_start = '$encoder.jsEscape( $i18n.getString( "start" ) , "'" )';
+	var i18n_stop = '$encoder.jsEscape( $i18n.getString( "stop" ) , "'" )';
+	var i18n_scheduling_is = '$encoder.jsEscape( $i18n.getString( "scheduling_is" ) , "'" )';
+</script>
\ No newline at end of file