You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ra...@apache.org on 2016/11/14 14:06:11 UTC

[09/14] incubator-fineract git commit: SMS Campaign feature implementation

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/data/SmsCampaignTimeLine.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/data/SmsCampaignTimeLine.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/data/SmsCampaignTimeLine.java
new file mode 100644
index 0000000..faf6073
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/data/SmsCampaignTimeLine.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.data;
+
+import org.joda.time.LocalDate;
+
+@SuppressWarnings("unused")
+public class SmsCampaignTimeLine {
+
+    private final LocalDate submittedOnDate;
+    private final String submittedByUsername;
+
+    private final LocalDate activatedOnDate;
+    private final String activatedByUsername;
+
+    private final LocalDate closedOnDate;
+    private final String closedByUsername;
+
+    public SmsCampaignTimeLine(final LocalDate submittedOnDate, final String submittedByUsername, final LocalDate activatedOnDate,
+            final String activatedByUsername, final LocalDate closedOnDate, final String closedByUsername) {
+        this.submittedOnDate = submittedOnDate;
+        this.submittedByUsername = submittedByUsername;
+        this.activatedOnDate = activatedOnDate;
+        this.activatedByUsername = activatedByUsername;
+        this.closedOnDate = closedOnDate;
+        this.closedByUsername = closedByUsername;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/data/SmsProviderData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/data/SmsProviderData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/data/SmsProviderData.java
new file mode 100644
index 0000000..9ae9768
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/data/SmsProviderData.java
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.data;
+
+public class SmsProviderData {
+
+    private Long id;
+
+    private String tenantId;
+    
+    private String phoneNo;
+    
+    private String providerAppKey;
+
+    private String providerName;
+
+    private String providerDescription;
+
+    public SmsProviderData(final Long id, final String providerAppKey, final String providerName, final String providerDescription, final String tenantId, 
+            final String phoneNo) {
+        this.id = id;
+        this.providerAppKey = providerAppKey;
+        this.providerName = providerName;
+        this.providerDescription = providerDescription;
+        this.tenantId = tenantId;
+        this.phoneNo = phoneNo;
+    }
+    
+    public SmsProviderData() {
+        
+    }
+
+    public Long getId() {
+        return this.id;
+    }
+
+    public String getProviderAppKey() {
+        return this.providerAppKey;
+    }
+
+    public String getProviderName() {
+        return this.providerName;
+    }
+
+    public String getProviderDescription() {
+        return this.providerDescription;
+    }
+
+    public String getTenantId() {
+        return this.tenantId;
+    }
+
+    public String getPhoneNo() {
+        return this.phoneNo;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/data/TriggerTypeWithSubTypesData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/data/TriggerTypeWithSubTypesData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/data/TriggerTypeWithSubTypesData.java
new file mode 100644
index 0000000..b6e9c3c
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/data/TriggerTypeWithSubTypesData.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.data;
+
+import java.util.List;
+
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+
+public class TriggerTypeWithSubTypesData {
+
+    private final EnumOptionData actualTriggerType;
+    private final List<EnumOptionData> triggerSubTypes;
+
+    public TriggerTypeWithSubTypesData(final EnumOptionData actualTriggerType, List<EnumOptionData> triggerSubTypes) {
+        this.actualTriggerType = actualTriggerType;
+        this.triggerSubTypes = triggerSubTypes;
+    }
+
+    public EnumOptionData getActualTriggerType() {
+        return this.actualTriggerType;
+    }
+
+    public List<EnumOptionData> getTriggerSubTypes() {
+        return this.triggerSubTypes;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/domain/SmsCampaign.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/domain/SmsCampaign.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/domain/SmsCampaign.java
new file mode 100644
index 0000000..3e1610e
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/domain/SmsCampaign.java
@@ -0,0 +1,561 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.domain;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.UniqueConstraint;
+
+import org.apache.commons.lang.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.fineract.infrastructure.campaigns.constants.CampaignType;
+import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignStatus;
+import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignTriggerType;
+import org.apache.fineract.infrastructure.campaigns.sms.serialization.SmsCampaignValidator;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.ApiParameterError;
+import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
+import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
+import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.dataqueries.domain.Report;
+import org.apache.fineract.portfolio.calendar.domain.CalendarFrequencyType;
+import org.apache.fineract.portfolio.calendar.domain.CalendarWeekDaysType;
+import org.apache.fineract.useradministration.domain.AppUser;
+import org.joda.time.LocalDate;
+import org.joda.time.LocalDateTime;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+
+@Entity
+@Table(name = "sms_campaign", uniqueConstraints = {@UniqueConstraint(columnNames = { "campaign_name" }, name = "campaign_name_UNIQUE")})
+public class SmsCampaign extends AbstractPersistableCustom<Long> {
+
+    @Column(name = "campaign_name", nullable = false)
+    private String campaignName;
+
+    @Column(name = "campaign_type", nullable = false)
+    private Integer campaignType ; //defines email or sms, etc..
+    
+    @Column(name = "campaign_trigger_type", nullable = false)
+    private Integer triggerType; //defines direct, scheduled, transaction
+    
+    @Column(name = "provider_id", nullable = false)
+    private Long providerId; // defined provider details
+
+    @ManyToOne
+    @JoinColumn(name = "report_id", nullable = false)
+    private Report businessRuleId;
+
+    @Column(name = "param_value")
+    private String paramValue;
+
+    @Column(name = "status_enum", nullable = false)
+    private Integer status;
+
+    @Column(name = "message", nullable = false)
+    private String message;
+
+    @Column(name = "closedon_date", nullable = true)
+    @Temporal(TemporalType.DATE)
+    private Date closureDate;
+
+    @ManyToOne(optional = true)
+    @JoinColumn(name = "closedon_userid", nullable = true)
+    private AppUser closedBy;
+
+    @Column(name = "submittedon_date", nullable = true)
+    @Temporal(TemporalType.DATE)
+    private Date submittedOnDate;
+
+    @ManyToOne(optional = true)
+    @JoinColumn(name = "submittedon_userid", nullable = true)
+    private AppUser submittedBy;
+
+    @Column(name = "approvedon_date", nullable = true)
+    @Temporal(TemporalType.DATE)
+    private Date approvedOnDate;
+
+    @ManyToOne(optional = true)
+    @JoinColumn(name = "approvedon_userid", nullable = true)
+    private AppUser approvedBy;
+
+    @Column(name = "recurrence", nullable = true)
+    private String recurrence;
+
+    @Column(name = "next_trigger_date", nullable = true)
+    @Temporal(TemporalType.TIMESTAMP)
+    private Date nextTriggerDate;
+
+    @Column(name = "last_trigger_date", nullable = true)
+    @Temporal(TemporalType.TIMESTAMP)
+    private Date lastTriggerDate;
+
+    @Column(name = "recurrence_start_date", nullable = true)
+    @Temporal(TemporalType.TIMESTAMP)
+    private Date recurrenceStartDate;
+
+    @Column(name = "is_visible", nullable = true)
+    private boolean isVisible;
+
+    public SmsCampaign() {}
+
+    private SmsCampaign(final String campaignName, final Integer campaignType, 
+            final Integer triggerType, final Report businessRuleId, final Long providerId, final String paramValue,
+            final String message, final LocalDate submittedOnDate, final AppUser submittedBy, final String recurrence,
+            final LocalDateTime localDateTime) {
+        this.campaignName = campaignName;
+        this.campaignType = campaignType;
+        this.triggerType = SmsCampaignTriggerType.fromInt(triggerType).getValue();
+        this.businessRuleId = businessRuleId;
+        this.providerId = providerId;
+        this.paramValue = paramValue;
+        this.status = SmsCampaignStatus.PENDING.getValue();
+        this.message = message;
+        this.submittedOnDate = submittedOnDate.toDate();
+        this.submittedBy = submittedBy;
+        this.recurrence = recurrence;
+        LocalDateTime recurrenceStartDate = new LocalDateTime();
+        this.isVisible = true;
+        if (localDateTime != null) {
+            this.recurrenceStartDate = localDateTime.toDate();
+        } else {
+            this.recurrenceStartDate = recurrenceStartDate.toDate();
+        }
+    }
+
+    public static SmsCampaign instance(final AppUser submittedBy, final Report report, final JsonCommand command) {
+
+        final String campaignName = command.stringValueOfParameterNamed(SmsCampaignValidator.campaignName);
+        final Long campaignType = command.longValueOfParameterNamed(SmsCampaignValidator.campaignType);
+        final Long triggerType = command.longValueOfParameterNamed(SmsCampaignValidator.triggerType);
+        final Long providerId = command.longValueOfParameterNamed(SmsCampaignValidator.providerId);
+        final String paramValue = command.jsonFragment(SmsCampaignValidator.paramValue);
+
+        final String message = command.stringValueOfParameterNamed(SmsCampaignValidator.message);
+        LocalDate submittedOnDate = new LocalDate();
+        if (command.hasParameter(SmsCampaignValidator.submittedOnDateParamName)) {
+            submittedOnDate = command.localDateValueOfParameterNamed(SmsCampaignValidator.submittedOnDateParamName);
+        }
+        String recurrence = null;
+
+        LocalDateTime recurrenceStartDate = new LocalDateTime();
+        if (SmsCampaignTriggerType.fromInt(triggerType.intValue()).isSchedule()) {
+            final Locale locale = command.extractLocale();
+            String dateTimeFormat = null;
+            if (command.hasParameter(SmsCampaignValidator.dateTimeFormat)) {
+                dateTimeFormat = command.stringValueOfParameterNamed(SmsCampaignValidator.dateTimeFormat);
+                final DateTimeFormatter fmt = DateTimeFormat.forPattern(dateTimeFormat).withLocale(locale);
+                if (command.hasParameter(SmsCampaignValidator.recurrenceStartDate)) {
+                    recurrenceStartDate = LocalDateTime.parse(
+                            command.stringValueOfParameterNamed(SmsCampaignValidator.recurrenceStartDate), fmt);
+                }
+                recurrence = constructRecurrence(command);
+            }
+        } else {
+            recurrenceStartDate = null;
+        }
+
+        return new SmsCampaign(campaignName, campaignType.intValue(), triggerType.intValue(), report,
+                providerId, paramValue, message, submittedOnDate, submittedBy, recurrence, recurrenceStartDate);
+    }
+
+    public Map<String, Object> update(JsonCommand command) {
+
+        final Map<String, Object> actualChanges = new LinkedHashMap<>(5);
+
+        if (command.isChangeInStringParameterNamed(SmsCampaignValidator.campaignName, this.campaignName)) {
+            final String newValue = command.stringValueOfParameterNamed(SmsCampaignValidator.campaignName);
+            actualChanges.put(SmsCampaignValidator.campaignName, newValue);
+            this.campaignName = StringUtils.defaultIfEmpty(newValue, null);
+        }
+        if (command.isChangeInStringParameterNamed(SmsCampaignValidator.message, this.message)) {
+            final String newValue = command.stringValueOfParameterNamed(SmsCampaignValidator.message);
+            actualChanges.put(SmsCampaignValidator.message, newValue);
+            this.message = StringUtils.defaultIfEmpty(newValue, null);
+        }
+        if (command.isChangeInStringParameterNamed(SmsCampaignValidator.paramValue, this.paramValue)) {
+            final String newValue = command.jsonFragment(SmsCampaignValidator.paramValue);
+            actualChanges.put(SmsCampaignValidator.paramValue, newValue);
+            this.paramValue = StringUtils.defaultIfEmpty(newValue, null);
+        }
+        if (command.isChangeInIntegerParameterNamed(SmsCampaignValidator.campaignType, this.campaignType)) {
+            final Integer newValue = command.integerValueOfParameterNamed(SmsCampaignValidator.campaignType);
+            actualChanges.put(SmsCampaignValidator.campaignType, CampaignType.fromInt(newValue));
+            this.campaignType = CampaignType.fromInt(newValue).getValue();
+        }
+
+        if (command.isChangeInIntegerParameterNamed(SmsCampaignValidator.triggerType, this.triggerType)) {
+            final Integer newValue = command.integerValueOfParameterNamed(SmsCampaignValidator.triggerType);
+            actualChanges.put(SmsCampaignValidator.triggerType, SmsCampaignTriggerType.fromInt(newValue));
+            this.triggerType = SmsCampaignTriggerType.fromInt(newValue).getValue();
+        }
+
+        if (command.isChangeInLongParameterNamed(SmsCampaignValidator.runReportId,
+                (this.businessRuleId != null) ? this.businessRuleId.getId() : null)) {
+            final String newValue = command.stringValueOfParameterNamed(SmsCampaignValidator.runReportId);
+            actualChanges.put(SmsCampaignValidator.runReportId, newValue);
+        }
+        if (command.isChangeInStringParameterNamed(SmsCampaignValidator.recurrenceParamName, this.recurrence)) {
+            final String newValue = command.stringValueOfParameterNamed(SmsCampaignValidator.recurrenceParamName);
+            actualChanges.put(SmsCampaignValidator.recurrenceParamName, newValue);
+            this.recurrence = StringUtils.defaultIfEmpty(newValue, null);
+        }
+        if (command.isChangeInLongParameterNamed(SmsCampaignValidator.providerId, this.providerId)) {
+            final Long newValue = command.longValueOfParameterNamed(SmsCampaignValidator.providerId);
+            actualChanges.put(SmsCampaignValidator.providerId, newValue);
+        }
+
+        if (SmsCampaignTriggerType.fromInt(this.triggerType).isSchedule()) {
+            final String dateFormatAsInput = command.dateFormat();
+            final String dateTimeFormatAsInput = command.stringValueOfParameterNamed(SmsCampaignValidator.dateTimeFormat);
+            final String localeAsInput = command.locale();
+            final Locale locale = command.extractLocale();
+            final DateTimeFormatter fmt = DateTimeFormat.forPattern(dateTimeFormatAsInput).withLocale(locale);
+            final String valueAsInput = command.stringValueOfParameterNamed(SmsCampaignValidator.recurrenceStartDate);
+            actualChanges.put(SmsCampaignValidator.recurrenceStartDate, valueAsInput);
+            actualChanges.put(SmsCampaignValidator.dateFormatParamName, dateFormatAsInput);
+            actualChanges.put(SmsCampaignValidator.dateTimeFormat, dateTimeFormatAsInput);
+            actualChanges.put(SmsCampaignValidator.localeParamName, localeAsInput);
+
+            final LocalDateTime newValue = LocalDateTime.parse(valueAsInput, fmt);
+
+            this.recurrenceStartDate = newValue.toDate();
+        }
+
+        return actualChanges;
+    }
+
+    public void activate(final AppUser currentUser, final DateTimeFormatter formatter, final LocalDate activationLocalDate) {
+
+        if (isActive()) {
+            // handle errors if already activated
+            final String defaultUserMessage = "Cannot activate campaign. Campaign is already active.";
+            final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.already.active", defaultUserMessage,
+                    SmsCampaignValidator.activationDateParamName, activationLocalDate.toString(formatter));
+
+            final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+            dataValidationErrors.add(error);
+
+            throw new PlatformApiDataValidationException(dataValidationErrors);
+        }
+        this.approvedOnDate = activationLocalDate.toDate();
+        this.approvedBy = currentUser;
+        this.status = SmsCampaignStatus.ACTIVE.getValue();
+
+        validate();
+    }
+
+    public void close(final AppUser currentUser, final DateTimeFormatter dateTimeFormatter, final LocalDate closureLocalDate) {
+        if (isClosed()) {
+            // handle errors if already activated
+            final String defaultUserMessage = "Cannot close campaign. Campaign already in closed state.";
+            final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.already.closed", defaultUserMessage,
+                    SmsCampaignValidator.statusParamName, SmsCampaignStatus.fromInt(this.status).getCode());
+
+            final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+            dataValidationErrors.add(error);
+
+            throw new PlatformApiDataValidationException(dataValidationErrors);
+        }
+        if (this.triggerType.intValue() == SmsCampaignTriggerType.SCHEDULE.getValue()) {
+            this.nextTriggerDate = null;
+            this.lastTriggerDate = null;
+        }
+        this.closedBy = currentUser;
+        this.closureDate = closureLocalDate.toDate();
+        this.status = SmsCampaignStatus.CLOSED.getValue();
+        validateClosureDate();
+    }
+
+    public void reactivate(final AppUser currentUser, final DateTimeFormatter dateTimeFormat, final LocalDate reactivateLocalDate) {
+
+        if (!isClosed()) {
+            // handle errors if already activated
+            final String defaultUserMessage = "Cannot reactivate campaign. Campaign must be in closed state.";
+            final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.must.be.closed", defaultUserMessage,
+                    SmsCampaignValidator.statusParamName, SmsCampaignStatus.fromInt(this.status).getCode());
+
+            final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+            dataValidationErrors.add(error);
+
+            throw new PlatformApiDataValidationException(dataValidationErrors);
+        }
+
+        this.approvedOnDate = reactivateLocalDate.toDate();
+        this.status = SmsCampaignStatus.ACTIVE.getValue();
+        this.approvedBy = currentUser;
+        this.closureDate = null;
+        this.isVisible = true;
+        this.closedBy = null;
+
+        validateReactivate();
+    }
+
+    public void delete() {
+        if (!isClosed()) {
+            // handle errors if already activated
+            final String defaultUserMessage = "Cannot delete campaign. Campaign must be in closed state.";
+            final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.must.be.closed", defaultUserMessage,
+                    SmsCampaignValidator.statusParamName, SmsCampaignStatus.fromInt(this.status).getCode());
+
+            final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+            dataValidationErrors.add(error);
+
+            throw new PlatformApiDataValidationException(dataValidationErrors);
+        }
+        this.isVisible = false;
+    }
+
+    public boolean isActive() {
+        return SmsCampaignStatus.fromInt(this.status).isActive();
+    }
+
+    public boolean isPending() {
+        return SmsCampaignStatus.fromInt(this.status).isPending();
+    }
+
+    public boolean isClosed() {
+        return SmsCampaignStatus.fromInt(this.status).isClosed();
+    }
+
+    public boolean isDirect() {
+        return SmsCampaignTriggerType.fromInt(this.triggerType).isDirect();
+    }
+
+    public boolean isSchedule() {
+        return SmsCampaignTriggerType.fromInt(this.triggerType).isSchedule();
+    }
+
+    public boolean isTriggered() {
+        return SmsCampaignTriggerType.fromInt(this.triggerType).isTriggered();
+    }
+
+    private void validate() {
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        validateActivationDate(dataValidationErrors);
+        if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
+    }
+
+    private void validateReactivate() {
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        validateReactivationDate(dataValidationErrors);
+        if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
+    }
+
+    private void validateClosureDate() {
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        validateClosureDate(dataValidationErrors);
+        if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
+    }
+
+    private void validateActivationDate(final List<ApiParameterError> dataValidationErrors) {
+
+        if (getSubmittedOnDate() != null && isDateInTheFuture(getSubmittedOnDate())) {
+
+            final String defaultUserMessage = "submitted date cannot be in the future.";
+            final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.submittedOnDate.in.the.future",
+                    defaultUserMessage, SmsCampaignValidator.submittedOnDateParamName, this.submittedOnDate);
+
+            dataValidationErrors.add(error);
+        }
+
+        if (getActivationLocalDate() != null && getSubmittedOnDate() != null && getSubmittedOnDate().isAfter(getActivationLocalDate())) {
+
+            final String defaultUserMessage = "submitted date cannot be after the activation date";
+            final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.submittedOnDate.after.activation.date",
+                    defaultUserMessage, SmsCampaignValidator.submittedOnDateParamName, this.submittedOnDate);
+
+            dataValidationErrors.add(error);
+        }
+
+        if (getActivationLocalDate() != null && isDateInTheFuture(getActivationLocalDate())) {
+
+            final String defaultUserMessage = "Activation date cannot be in the future.";
+            final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.activationDate.in.the.future",
+                    defaultUserMessage, SmsCampaignValidator.activationDateParamName, getActivationLocalDate());
+
+            dataValidationErrors.add(error);
+        }
+
+    }
+
+    private void validateReactivationDate(final List<ApiParameterError> dataValidationErrors) {
+        if (getActivationLocalDate() != null && isDateInTheFuture(getActivationLocalDate())) {
+
+            final String defaultUserMessage = "Activation date cannot be in the future.";
+            final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.activationDate.in.the.future",
+                    defaultUserMessage, SmsCampaignValidator.activationDateParamName, getActivationLocalDate());
+
+            dataValidationErrors.add(error);
+        }
+        if (getActivationLocalDate() != null && getSubmittedOnDate() != null && getSubmittedOnDate().isAfter(getActivationLocalDate())) {
+
+            final String defaultUserMessage = "submitted date cannot be after the activation date";
+            final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.submittedOnDate.after.activation.date",
+                    defaultUserMessage, SmsCampaignValidator.submittedOnDateParamName, this.submittedOnDate);
+
+            dataValidationErrors.add(error);
+        }
+        if (getSubmittedOnDate() != null && isDateInTheFuture(getSubmittedOnDate())) {
+
+            final String defaultUserMessage = "submitted date cannot be in the future.";
+            final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.submittedOnDate.in.the.future",
+                    defaultUserMessage, SmsCampaignValidator.submittedOnDateParamName, this.submittedOnDate);
+
+            dataValidationErrors.add(error);
+        }
+
+    }
+
+    private void validateClosureDate(final List<ApiParameterError> dataValidationErrors) {
+        if (getClosureDate() != null && isDateInTheFuture(getClosureDate())) {
+            final String defaultUserMessage = "closure date cannot be in the future.";
+            final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.closureDate.in.the.future",
+                    defaultUserMessage, SmsCampaignValidator.closureDateParamName, this.closureDate);
+
+            dataValidationErrors.add(error);
+        }
+    }
+
+    public LocalDate getSubmittedOnDate() {
+        return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.submittedOnDate), null);
+
+    }
+
+    public LocalDate getClosureDate() {
+        return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.closureDate), null);
+    }
+
+    public LocalDate getActivationLocalDate() {
+        LocalDate activationLocalDate = null;
+        if (this.approvedOnDate != null) {
+            activationLocalDate = LocalDate.fromDateFields(this.approvedOnDate);
+        }
+        return activationLocalDate;
+    }
+
+    private boolean isDateInTheFuture(final LocalDate localDate) {
+        return localDate.isAfter(DateUtils.getLocalDateOfTenant());
+    }
+
+    public Report getBusinessRuleId() {
+        return this.businessRuleId;
+    }
+
+    public String getCampaignName() {
+        return this.campaignName;
+    }
+
+    public String getMessage() {
+        return this.message;
+    }
+
+    public String getParamValue() {
+        return this.paramValue;
+    }
+
+    public String getRecurrence() {
+        return this.recurrence;
+    }
+
+    public LocalDate getRecurrenceStartDate() {
+        return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.recurrenceStartDate), null);
+    }
+
+    public LocalDateTime getRecurrenceStartDateTime() {
+        return (LocalDateTime) ObjectUtils.defaultIfNull(new LocalDateTime(this.recurrenceStartDate), null);
+    }
+
+    public void setLastTriggerDate(Date lastTriggerDate) {
+        this.lastTriggerDate = lastTriggerDate;
+    }
+
+    public void setNextTriggerDate(Date nextTriggerDate) {
+        this.nextTriggerDate = nextTriggerDate;
+    }
+
+    public LocalDateTime getNextTriggerDate() {
+        return (LocalDateTime) ObjectUtils.defaultIfNull(new LocalDateTime(this.nextTriggerDate), null);
+
+    }
+
+    public Date getNextTriggerDateInDate() {
+        return this.nextTriggerDate;
+    }
+
+    public LocalDate getLastTriggerDate() {
+        return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.lastTriggerDate), null);
+    }
+
+    public void updateIsVisible(boolean isVisible) {
+        this.isVisible = isVisible;
+    }
+
+    public void updateBusinessRuleId(final Report report) {
+        this.businessRuleId = report;
+    }
+
+    public Long getProviderId() {
+        return this.providerId;
+    }
+
+    private static String constructRecurrence(final JsonCommand command) {
+        final Integer frequency = command.integerValueOfParameterNamed(SmsCampaignValidator.frequencyParamName);
+        final CalendarFrequencyType frequencyType = CalendarFrequencyType.fromInt(frequency);
+        final Integer interval = command.integerValueOfParameterNamed(SmsCampaignValidator.intervalParamName);
+        Integer repeatsOnDay = null;
+        if (frequencyType.isWeekly()) {
+            repeatsOnDay = command.integerValueOfParameterNamed(SmsCampaignValidator.repeatsOnDayParamName);
+        }
+        return constructRecurrence(frequencyType, interval, repeatsOnDay);
+    }
+
+    private static String constructRecurrence(final CalendarFrequencyType frequencyType, final Integer interval, final Integer repeatsOnDay) {
+        final StringBuilder recurrenceBuilder = new StringBuilder(200);
+
+        recurrenceBuilder.append("FREQ=");
+        recurrenceBuilder.append(frequencyType.toString().toUpperCase());
+        if (interval > 1) {
+            recurrenceBuilder.append(";INTERVAL=");
+            recurrenceBuilder.append(interval);
+        }
+        if (frequencyType.isWeekly()) {
+            if (repeatsOnDay != null) {
+                final CalendarWeekDaysType weekDays = CalendarWeekDaysType.fromInt(repeatsOnDay);
+                if (!weekDays.isInvalid()) {
+                    recurrenceBuilder.append(";BYDAY=");
+                    recurrenceBuilder.append(weekDays.toString().toUpperCase());
+                }
+            }
+        }
+        return recurrenceBuilder.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/domain/SmsCampaignRepository.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/domain/SmsCampaignRepository.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/domain/SmsCampaignRepository.java
new file mode 100644
index 0000000..436f9ed
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/domain/SmsCampaignRepository.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.domain;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+public interface SmsCampaignRepository extends JpaRepository<SmsCampaign, Long>, JpaSpecificationExecutor<SmsCampaign> {
+
+    List<SmsCampaign> findByCampaignType(final Integer campaignType);
+
+    Collection<SmsCampaign> findByCampaignTypeAndTriggerTypeAndStatus(final Integer campaignType, final Integer triggerType,
+            final Integer status);
+
+    Collection<SmsCampaign> findByTriggerType(final Integer triggerType) ;
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/domain/SmsCampaignStatusEnumerations.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/domain/SmsCampaignStatusEnumerations.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/domain/SmsCampaignStatusEnumerations.java
new file mode 100644
index 0000000..9147a29
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/domain/SmsCampaignStatusEnumerations.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.domain;
+
+import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignStatus;
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+
+public class SmsCampaignStatusEnumerations {
+    public static EnumOptionData status(final Integer statusId) {
+        return status(SmsCampaignStatus.fromInt(statusId));
+    }
+
+    public static EnumOptionData status(final SmsCampaignStatus status) {
+        EnumOptionData optionData = new EnumOptionData(SmsCampaignStatus.INVALID.getValue().longValue(),
+                SmsCampaignStatus.INVALID.getCode(), "Invalid");
+        switch (status) {
+            case INVALID:
+                optionData = new EnumOptionData
+                (SmsCampaignStatus.INVALID.getValue().longValue(),
+                        SmsCampaignStatus.INVALID.getCode(), "Invalid");
+                break;
+            case PENDING:
+                optionData = new EnumOptionData(SmsCampaignStatus.PENDING.getValue().longValue(),
+                        SmsCampaignStatus.PENDING.getCode(), "Pending");
+                break;
+            case ACTIVE:
+                optionData = new EnumOptionData(SmsCampaignStatus.ACTIVE.getValue().longValue(), SmsCampaignStatus.ACTIVE.getCode(),
+                        "active");
+                break;
+            case CLOSED:
+                optionData = new EnumOptionData(SmsCampaignStatus.CLOSED.getValue().longValue(),
+                        SmsCampaignStatus.CLOSED.getCode(), "closed");
+                break;
+
+        }
+
+        return optionData;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/ConnectionFailureException.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/ConnectionFailureException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/ConnectionFailureException.java
new file mode 100644
index 0000000..b7d9d97
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/ConnectionFailureException.java
@@ -0,0 +1,30 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.exception;
+
+import org.apache.fineract.infrastructure.core.exception.AbstractPlatformServiceUnavailableException;
+
+public class ConnectionFailureException extends AbstractPlatformServiceUnavailableException {
+
+    public ConnectionFailureException(final String connectionName) {
+        super("error.msg.unable.to.connect.to.intermediate.server", "Unable to connect to the server with connection name - "
+                + connectionName, connectionName);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/GatewayConnectionConfigurationNotFound.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/GatewayConnectionConfigurationNotFound.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/GatewayConnectionConfigurationNotFound.java
new file mode 100644
index 0000000..cf9a31a
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/GatewayConnectionConfigurationNotFound.java
@@ -0,0 +1,30 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.exception;
+
+import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
+
+public class GatewayConnectionConfigurationNotFound extends AbstractPlatformResourceNotFoundException {
+
+    public GatewayConnectionConfigurationNotFound(String connectionName) {
+        super("error.msg.gateway.config.not.found", "Gateway Connection Configuration with name `" + connectionName + "` does not exist",
+                connectionName);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/SmsCampaignMustBeClosedToBeDeletedException.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/SmsCampaignMustBeClosedToBeDeletedException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/SmsCampaignMustBeClosedToBeDeletedException.java
new file mode 100644
index 0000000..96fd8d3
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/SmsCampaignMustBeClosedToBeDeletedException.java
@@ -0,0 +1,28 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.exception;
+
+import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
+
+public class SmsCampaignMustBeClosedToBeDeletedException  extends AbstractPlatformDomainRuleException {
+
+    public SmsCampaignMustBeClosedToBeDeletedException(final Long resourceId) {
+        super("error.msg.sms.campaign.cannot.be.deleted",
+                "Campaign with identifier " + resourceId + " cannot be deleted as it is not in `Closed` state.", resourceId);    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/SmsCampaignMustBeClosedToEditException.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/SmsCampaignMustBeClosedToEditException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/SmsCampaignMustBeClosedToEditException.java
new file mode 100644
index 0000000..5798d8f
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/SmsCampaignMustBeClosedToEditException.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.exception;
+
+import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
+
+public class SmsCampaignMustBeClosedToEditException extends AbstractPlatformDomainRuleException {
+
+    public SmsCampaignMustBeClosedToEditException(final Long resourceId) {
+        super("error.msg.sms.campaign.cannot.be.updated",
+                "Campaign with identifier " + resourceId + " cannot be updated as it is not in `Closed` state.", resourceId);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/SmsCampaignNotFound.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/SmsCampaignNotFound.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/SmsCampaignNotFound.java
new file mode 100644
index 0000000..6bf0f47
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/exception/SmsCampaignNotFound.java
@@ -0,0 +1,28 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.exception;
+
+import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
+
+public class SmsCampaignNotFound extends AbstractPlatformResourceNotFoundException{
+
+    public SmsCampaignNotFound(final Long resourceId) {
+        super("error.msg.sms.campaign.identifier.not.found", "Sms Campaign with identifier `" + resourceId + "` does not exist", resourceId);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/ActivateSmsCampaignCommandHandler.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/ActivateSmsCampaignCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/ActivateSmsCampaignCommandHandler.java
new file mode 100644
index 0000000..a6b56d3
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/ActivateSmsCampaignCommandHandler.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.handler;
+
+import org.apache.fineract.commands.annotation.CommandType;
+import org.apache.fineract.commands.handler.NewCommandSourceHandler;
+import org.apache.fineract.infrastructure.campaigns.sms.service.SmsCampaignWritePlatformService;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@CommandType(entity = "SMSCAMPAIGN", action = "ACTIVATE")
+public class ActivateSmsCampaignCommandHandler implements NewCommandSourceHandler {
+
+    private SmsCampaignWritePlatformService smsCampaignWritePlatformService;
+
+    @Autowired
+    public ActivateSmsCampaignCommandHandler(final SmsCampaignWritePlatformService smsCampaignWritePlatformService) {
+        this.smsCampaignWritePlatformService = smsCampaignWritePlatformService;
+    }
+
+    @Transactional
+    @Override
+    public CommandProcessingResult processCommand(JsonCommand command) {
+        return this.smsCampaignWritePlatformService.activateSmsCampaign(command.entityId(), command);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/CloseSmsCampaignCommandHandler.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/CloseSmsCampaignCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/CloseSmsCampaignCommandHandler.java
new file mode 100644
index 0000000..0f1217e
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/CloseSmsCampaignCommandHandler.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.handler;
+
+import org.apache.fineract.commands.annotation.CommandType;
+import org.apache.fineract.commands.handler.NewCommandSourceHandler;
+import org.apache.fineract.infrastructure.campaigns.sms.service.SmsCampaignWritePlatformService;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+@CommandType(entity = "SMSCAMPAIGN", action = "CLOSE")
+public class CloseSmsCampaignCommandHandler implements NewCommandSourceHandler {
+    private final SmsCampaignWritePlatformService smsCampaignWritePlatformService;
+
+   @Autowired
+    public CloseSmsCampaignCommandHandler(final SmsCampaignWritePlatformService smsCampaignWritePlatformService) {
+        this.smsCampaignWritePlatformService = smsCampaignWritePlatformService;
+    }
+
+    @Override
+    public CommandProcessingResult processCommand(JsonCommand command) {
+       return this.smsCampaignWritePlatformService.closeSmsCampaign(command.entityId(), command);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/CreateSmsCampaignCommandHandler.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/CreateSmsCampaignCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/CreateSmsCampaignCommandHandler.java
new file mode 100644
index 0000000..687d9af
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/CreateSmsCampaignCommandHandler.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.handler;
+
+import org.apache.fineract.commands.annotation.CommandType;
+import org.apache.fineract.commands.handler.NewCommandSourceHandler;
+import org.apache.fineract.infrastructure.campaigns.sms.service.SmsCampaignWritePlatformService;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@CommandType(entity = "SMSCAMPAIGN", action = "CREATE")
+public class CreateSmsCampaignCommandHandler implements NewCommandSourceHandler {
+
+    private SmsCampaignWritePlatformService smsCampaignWritePlatformService;
+
+    @Autowired
+    public CreateSmsCampaignCommandHandler(final SmsCampaignWritePlatformService smsCampaignWritePlatformService) {
+        this.smsCampaignWritePlatformService = smsCampaignWritePlatformService;
+    }
+
+    @Transactional
+    @Override
+    public CommandProcessingResult processCommand(JsonCommand command) {
+        return this.smsCampaignWritePlatformService.create(command);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/DeleteSmsCampaignCommandHandler.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/DeleteSmsCampaignCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/DeleteSmsCampaignCommandHandler.java
new file mode 100644
index 0000000..ebb5ca5
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/DeleteSmsCampaignCommandHandler.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.handler;
+
+import org.apache.fineract.commands.annotation.CommandType;
+import org.apache.fineract.commands.handler.NewCommandSourceHandler;
+import org.apache.fineract.infrastructure.campaigns.sms.service.SmsCampaignWritePlatformService;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@CommandType(entity = "SMSCAMPAIGN", action = "DELETE")
+public class DeleteSmsCampaignCommandHandler implements NewCommandSourceHandler {
+
+    private final SmsCampaignWritePlatformService smsCampaignWritePlatformService;
+
+    @Autowired
+    public DeleteSmsCampaignCommandHandler(SmsCampaignWritePlatformService smsCampaignWritePlatformService) {
+        this.smsCampaignWritePlatformService = smsCampaignWritePlatformService;
+    }
+    @Transactional
+    @Override
+    public CommandProcessingResult processCommand(JsonCommand command) {
+       return this.smsCampaignWritePlatformService.delete(command.entityId());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/ReactivateSmsCampaignCommandHandler.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/ReactivateSmsCampaignCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/ReactivateSmsCampaignCommandHandler.java
new file mode 100644
index 0000000..aa8bebe
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/ReactivateSmsCampaignCommandHandler.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.handler;
+
+import org.apache.fineract.commands.annotation.CommandType;
+import org.apache.fineract.commands.handler.NewCommandSourceHandler;
+import org.apache.fineract.infrastructure.campaigns.sms.service.SmsCampaignWritePlatformService;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@CommandType(entity = "SMSCAMPAIGN", action = "REACTIVATE")
+public class ReactivateSmsCampaignCommandHandler implements NewCommandSourceHandler {
+
+    private final SmsCampaignWritePlatformService smsCampaignWritePlatformService;
+
+    @Autowired
+    public ReactivateSmsCampaignCommandHandler(SmsCampaignWritePlatformService smsCampaignWritePlatformService) {
+        this.smsCampaignWritePlatformService = smsCampaignWritePlatformService;
+    }
+    @Transactional
+    @Override
+    public CommandProcessingResult processCommand(JsonCommand command) {
+        return this.smsCampaignWritePlatformService.reactivateSmsCampaign(command.entityId(),command);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/UpdateSmsCampaignCommandHandler.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/UpdateSmsCampaignCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/UpdateSmsCampaignCommandHandler.java
new file mode 100644
index 0000000..e3c7f66
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/handler/UpdateSmsCampaignCommandHandler.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.handler;
+
+import org.apache.fineract.commands.annotation.CommandType;
+import org.apache.fineract.commands.handler.NewCommandSourceHandler;
+import org.apache.fineract.infrastructure.campaigns.sms.service.SmsCampaignWritePlatformService;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@CommandType(entity = "SMSCAMPAIGN", action = "UPDATE")
+public class UpdateSmsCampaignCommandHandler implements NewCommandSourceHandler {
+
+    private SmsCampaignWritePlatformService smsCampaignWritePlatformService;
+
+    @Autowired
+    public UpdateSmsCampaignCommandHandler(final SmsCampaignWritePlatformService smsCampaignWritePlatformService) {
+        this.smsCampaignWritePlatformService = smsCampaignWritePlatformService;
+    }
+
+    @Transactional
+    @Override
+    public CommandProcessingResult processCommand(JsonCommand command) {
+        return this.smsCampaignWritePlatformService.update(command.entityId(), command);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/serialization/SmsCampaignValidator.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/serialization/SmsCampaignValidator.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/serialization/SmsCampaignValidator.java
new file mode 100644
index 0000000..9484054
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/serialization/SmsCampaignValidator.java
@@ -0,0 +1,302 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.serialization;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignTriggerType;
+import org.apache.fineract.infrastructure.core.data.ApiParameterError;
+import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
+import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
+import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
+import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.portfolio.calendar.domain.CalendarFrequencyType;
+import org.joda.time.LocalDate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.google.gson.JsonElement;
+import com.google.gson.reflect.TypeToken;
+
+@Component
+public class SmsCampaignValidator {
+
+    public static final String RESOURCE_NAME = "sms";
+    public static final String campaignName = "campaignName";
+    public static final String campaignType = "campaignType";
+    public static final String triggerType = "triggerType";
+    public static final String triggerEntityType = "triggerEntityType";
+    public static final String triggerActionType = "triggerActionType";
+    public static final String providerId = "providerId";
+    public static final String runReportId = "runReportId";
+    public static final String paramValue = "paramValue";
+    public static final String message = "message";
+    public static final String activationDateParamName = "activationDate";
+    public static final String recurrenceStartDate = "recurrenceStartDate";
+    public static final String dateTimeFormat = "dateTimeFormat";
+    public static final String submittedOnDateParamName = "submittedOnDate";
+    public static final String closureDateParamName = "closureDate";
+    public static final String recurrenceParamName = "recurrence";
+    public static final String statusParamName = "status";
+
+    public static final String localeParamName = "locale";
+    public static final String dateFormatParamName = "dateFormat";
+    public static final String frequencyParamName = "frequency";
+    public static final String intervalParamName = "interval";
+    public static final String repeatsOnDayParamName = "repeatsOnDay";
+
+    private final FromJsonHelper fromApiJsonHelper;
+
+    public static final Set<String> supportedParams = new HashSet<>(Arrays.asList(campaignName, campaignType, localeParamName,
+            dateFormatParamName, runReportId, paramValue, message, recurrenceStartDate, activationDateParamName, submittedOnDateParamName,
+            closureDateParamName, recurrenceParamName, providerId, triggerType, frequencyParamName, intervalParamName,
+            repeatsOnDayParamName, triggerEntityType, triggerActionType, dateTimeFormat));
+
+    public static final Set<String> supportedParamsForUpdate = new HashSet<>(Arrays.asList(campaignName, campaignType, localeParamName,
+            dateFormatParamName, runReportId, paramValue, message, recurrenceStartDate, activationDateParamName, recurrenceParamName,
+            providerId, triggerType, triggerEntityType, triggerActionType, dateTimeFormat));
+
+    public static final Set<String> ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName, dateFormatParamName,
+            activationDateParamName));
+
+    public static final Set<String> CLOSE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName, dateFormatParamName,
+            closureDateParamName));
+
+    public static final Set<String> PREVIEW_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(paramValue, message));
+
+    @Autowired
+    public SmsCampaignValidator(FromJsonHelper fromApiJsonHelper) {
+        this.fromApiJsonHelper = fromApiJsonHelper;
+    }
+
+    public void validateCreate(String json) {
+        if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
+
+        final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
+        this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SmsCampaignValidator.supportedParams);
+
+        final JsonElement element = this.fromApiJsonHelper.parse(json);
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+
+        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
+                .resource(SmsCampaignValidator.RESOURCE_NAME);
+
+        final String campaignName = this.fromApiJsonHelper.extractStringNamed(SmsCampaignValidator.campaignName, element);
+        baseDataValidator.reset().parameter(SmsCampaignValidator.campaignName).value(campaignName).notBlank().notExceedingLengthOf(100);
+
+        final Long campaignType = this.fromApiJsonHelper.extractLongNamed(SmsCampaignValidator.campaignType, element);
+        baseDataValidator.reset().parameter(SmsCampaignValidator.campaignType).value(campaignType).notNull().integerGreaterThanZero();
+
+        final Long triggerType = this.fromApiJsonHelper.extractLongNamed(SmsCampaignValidator.triggerType, element);
+        baseDataValidator.reset().parameter(SmsCampaignValidator.triggerType).value(triggerType).notNull().integerGreaterThanZero();
+
+        if (triggerType.intValue() == SmsCampaignTriggerType.SCHEDULE.getValue()) {
+
+            final Integer frequencyParam = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(SmsCampaignValidator.frequencyParamName,
+                    element);
+            baseDataValidator.reset().parameter(SmsCampaignValidator.frequencyParamName).value(frequencyParam).notNull()
+                    .integerGreaterThanZero();
+
+            final String intervalParam = this.fromApiJsonHelper.extractStringNamed(SmsCampaignValidator.intervalParamName, element);
+            baseDataValidator.reset().parameter(SmsCampaignValidator.intervalParamName).value(intervalParam).notBlank();
+
+            if (frequencyParam != null && frequencyParam.equals(CalendarFrequencyType.WEEKLY.getValue())) {
+                final String repeatsOnDayParam = this.fromApiJsonHelper.extractStringNamed(SmsCampaignValidator.repeatsOnDayParamName,
+                        element);
+                baseDataValidator.reset().parameter(SmsCampaignValidator.repeatsOnDayParamName).value(repeatsOnDayParam).notBlank();
+            }
+            final String recurrenceStartDate = this.fromApiJsonHelper.extractStringNamed(SmsCampaignValidator.recurrenceStartDate, element);
+            baseDataValidator.reset().parameter(SmsCampaignValidator.recurrenceStartDate).value(recurrenceStartDate).notBlank();
+        } 
+
+        final Long runReportId = this.fromApiJsonHelper.extractLongNamed(SmsCampaignValidator.runReportId, element);
+        baseDataValidator.reset().parameter(SmsCampaignValidator.runReportId).value(runReportId).notNull().integerGreaterThanZero();
+        
+        final String message = this.fromApiJsonHelper.extractStringNamed(SmsCampaignValidator.message, element);
+        baseDataValidator.reset().parameter(SmsCampaignValidator.message).value(message).notBlank().notExceedingLengthOf(480);
+
+        final JsonElement paramValueJsonObject = this.fromApiJsonHelper.extractJsonObjectNamed(SmsCampaignValidator.paramValue, element);
+        if (triggerType.intValue() != SmsCampaignTriggerType.TRIGGERED.getValue()) {
+            baseDataValidator.reset().parameter(SmsCampaignValidator.paramValue).value(paramValueJsonObject).notBlank();
+            if (paramValueJsonObject != null && paramValueJsonObject.isJsonObject()) {
+                for (Map.Entry<String, JsonElement> entry : paramValueJsonObject.getAsJsonObject().entrySet()) {
+                    final JsonElement inner = entry.getValue();
+                    baseDataValidator.reset().parameter(entry.getKey()).value(inner).notBlank();
+                }
+            }
+        }
+
+        if (this.fromApiJsonHelper.parameterExists(SmsCampaignValidator.submittedOnDateParamName, element)) {
+            final LocalDate submittedOnDate = this.fromApiJsonHelper.extractLocalDateNamed(SmsCampaignValidator.submittedOnDateParamName,
+                    element);
+            baseDataValidator.reset().parameter(SmsCampaignValidator.submittedOnDateParamName).value(submittedOnDate).notNull();
+        }
+        throwExceptionIfValidationWarningsExist(dataValidationErrors);
+
+    }
+
+    public void validateForUpdate(String json) {
+        if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
+        final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
+        this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SmsCampaignValidator.supportedParamsForUpdate);
+        final JsonElement element = this.fromApiJsonHelper.parse(json);
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+
+        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
+                .resource(SmsCampaignValidator.RESOURCE_NAME);
+
+        final String campaignName = this.fromApiJsonHelper.extractStringNamed(SmsCampaignValidator.campaignName, element);
+        baseDataValidator.reset().parameter(SmsCampaignValidator.campaignName).value(campaignName).notBlank().notExceedingLengthOf(100);
+
+        final Long campaignType = this.fromApiJsonHelper.extractLongNamed(SmsCampaignValidator.campaignType, element);
+        baseDataValidator.reset().parameter(SmsCampaignValidator.campaignType).value(campaignType).notNull().integerGreaterThanZero();
+
+        final Long triggerType = this.fromApiJsonHelper.extractLongNamed(SmsCampaignValidator.triggerType, element);
+        baseDataValidator.reset().parameter(SmsCampaignValidator.triggerType).value(triggerType).notNull().integerGreaterThanZero();
+
+        if (triggerType.intValue() == SmsCampaignTriggerType.SCHEDULE.getValue()) {
+            if (this.fromApiJsonHelper.parameterExists(SmsCampaignValidator.recurrenceParamName, element)) {
+                final String recurrenceParamName = this.fromApiJsonHelper.extractStringNamed(SmsCampaignValidator.recurrenceParamName,
+                        element);
+                baseDataValidator.reset().parameter(SmsCampaignValidator.recurrenceParamName).value(recurrenceParamName).notBlank();
+            }
+            if (this.fromApiJsonHelper.parameterExists(SmsCampaignValidator.recurrenceStartDate, element)) {
+                final String recurrenceStartDate = this.fromApiJsonHelper.extractStringNamed(SmsCampaignValidator.recurrenceStartDate,
+                        element);
+                baseDataValidator.reset().parameter(SmsCampaignValidator.recurrenceStartDate).value(recurrenceStartDate).notBlank();
+            }
+        }
+
+        if(this.fromApiJsonHelper.parameterExists(SmsCampaignValidator.runReportId, element)) {
+            final Long runReportId = this.fromApiJsonHelper.extractLongNamed(SmsCampaignValidator.runReportId, element);
+            baseDataValidator.reset().parameter(SmsCampaignValidator.runReportId).value(runReportId).notNull().integerGreaterThanZero();
+        }
+
+        final String message = this.fromApiJsonHelper.extractStringNamed(SmsCampaignValidator.message, element);
+        baseDataValidator.reset().parameter(SmsCampaignValidator.message).value(message).notBlank().notExceedingLengthOf(480);
+
+        final JsonElement paramValueJsonObject = this.fromApiJsonHelper.extractJsonObjectNamed(SmsCampaignValidator.paramValue, element);
+        if (triggerType.intValue() != SmsCampaignTriggerType.TRIGGERED.getValue()) {
+            baseDataValidator.reset().parameter(SmsCampaignValidator.paramValue).value(paramValueJsonObject).notBlank();
+            if (paramValueJsonObject != null && paramValueJsonObject.isJsonObject()) {
+                for (Map.Entry<String, JsonElement> entry : paramValueJsonObject.getAsJsonObject().entrySet()) {
+                    final JsonElement inner = entry.getValue();
+                    baseDataValidator.reset().parameter(entry.getKey()).value(inner).notBlank();
+                }
+            }
+        }
+
+        throwExceptionIfValidationWarningsExist(dataValidationErrors);
+
+    }
+
+    public void validatePreviewMessage(String json) {
+        if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
+        final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
+        this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SmsCampaignValidator.PREVIEW_REQUEST_DATA_PARAMETERS);
+
+        final JsonElement element = this.fromApiJsonHelper.parse(json);
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
+                .resource(SmsCampaignValidator.RESOURCE_NAME);
+        final JsonElement paramValueJsonObject = this.fromApiJsonHelper.extractJsonObjectNamed(SmsCampaignValidator.paramValue, element);
+        baseDataValidator.reset().parameter(SmsCampaignValidator.paramValue).value(paramValueJsonObject).notBlank();
+        if (!paramValueJsonObject.isJsonNull() && paramValueJsonObject.isJsonObject()) {
+            for (Map.Entry<String, JsonElement> entry : paramValueJsonObject.getAsJsonObject().entrySet()) {
+                final JsonElement inner = entry.getValue();
+                baseDataValidator.reset().parameter(entry.getKey()).value(inner).notBlank();
+            }
+        }
+
+        final String message = this.fromApiJsonHelper.extractStringNamed(SmsCampaignValidator.message, element);
+        baseDataValidator.reset().parameter(SmsCampaignValidator.message).value(message).notBlank().notExceedingLengthOf(480);
+
+        throwExceptionIfValidationWarningsExist(dataValidationErrors);
+
+    }
+
+    public void validateClosedDate(String json) {
+        if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
+
+        final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
+        this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SmsCampaignValidator.CLOSE_REQUEST_DATA_PARAMETERS);
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
+                .resource(SmsCampaignValidator.RESOURCE_NAME);
+
+        final JsonElement element = this.fromApiJsonHelper.parse(json);
+
+        final LocalDate closeDate = this.fromApiJsonHelper.extractLocalDateNamed(SmsCampaignValidator.closureDateParamName, element);
+        baseDataValidator.reset().parameter(SmsCampaignValidator.closureDateParamName).value(closeDate).notNull();
+
+        throwExceptionIfValidationWarningsExist(dataValidationErrors);
+    }
+
+    public void validateActivation(String json) {
+        if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
+
+        final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
+        this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SmsCampaignValidator.ACTIVATION_REQUEST_DATA_PARAMETERS);
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
+                .resource(SmsCampaignValidator.RESOURCE_NAME);
+
+        final JsonElement element = this.fromApiJsonHelper.parse(json);
+
+        final LocalDate activationDate = this.fromApiJsonHelper
+                .extractLocalDateNamed(SmsCampaignValidator.activationDateParamName, element);
+        baseDataValidator.reset().parameter(SmsCampaignValidator.activationDateParamName).value(activationDate).notNull();
+
+        throwExceptionIfValidationWarningsExist(dataValidationErrors);
+    }
+
+    public void ValidateClosure(String json) {
+        if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
+
+        final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
+        this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SmsCampaignValidator.CLOSE_REQUEST_DATA_PARAMETERS);
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
+                .resource(SmsCampaignValidator.RESOURCE_NAME);
+
+        final JsonElement element = this.fromApiJsonHelper.parse(json);
+
+        final LocalDate closeDate = this.fromApiJsonHelper.extractLocalDateNamed(SmsCampaignValidator.closureDateParamName, element);
+        baseDataValidator.reset().parameter(SmsCampaignValidator.closureDateParamName).value(closeDate).notNull();
+
+        throwExceptionIfValidationWarningsExist(dataValidationErrors);
+    }
+
+    private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
+        if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDomainService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDomainService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDomainService.java
new file mode 100644
index 0000000..11faeb3
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDomainService.java
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.campaigns.sms.service;
+
+/**
+ * Created by Stefan on 4-7-2016.
+ */
+public interface SmsCampaignDomainService {
+}