SMS Campaign feature implementation
This commit is contained in:
+325
-2
@@ -2064,7 +2064,46 @@
|
||||
<td><a href="#shareproducts_retrieve">Retrieve a Share product</a></td>
|
||||
<td><a href="#shareproducts_update">Update a Share product</a></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><a href="#smscampaigns">SMS Campaigns</a></td>
|
||||
<td>smscampaigns</td>
|
||||
<td><a href="#smscampaigns_create">Create a SMS Campaign</a></td>
|
||||
<td><a href="#smscampaigns_list">List SMS Campaigns</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
tr>
|
||||
<td></td>
|
||||
<td>smscampaigns/{campaignId}</td>
|
||||
<td></td>
|
||||
<td><a href="#smscampaigns_retrieve">Retrieve a SMS Campaign</a></td>
|
||||
<td><a href="#smscampaigns_update">Update a SMS Campaign</a></td>
|
||||
<td><a href="#smscampaigns_delete">Delete a SMS Campaign</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>smscampaigns/{campaignId}command=activate</td>
|
||||
<td></td>
|
||||
<td><a href="#smscampaigns_activate">Activate a SMS Campaign</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>smscampaigns/{campaignId}command=close</td>
|
||||
<td></td>
|
||||
<td><a href="#smscampaigns_close">Close a SMS Campaign</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>smscampaigns/{campaignId}command=reactivate</td>
|
||||
<td></td>
|
||||
<td><a href="#smscampaigns_reactivate">Reactivate a SMS Campaign</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#configs">Currency</a></td>
|
||||
<td>currencies</td>
|
||||
@@ -21038,7 +21077,291 @@ Content-Type: application/json
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="shareproducts_create" name="shareproducts_create" class="old-syle-anchor"> </a>
|
||||
<a id="smscampaigns_create" name="smscampaigns_create" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>Create a SMS Campaign</h4>
|
||||
<table class=matrixHeading>
|
||||
<tr class="matrixHeadingBG"><td><div class="fineractHeading2">Mandatory Fields</div></td></tr>
|
||||
<tr class=alt>
|
||||
<td>campaignName, campaignType, triggerType, providerId, runReportId, message</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
<table class=matrixHeading>
|
||||
<tr class="matrixHeadingBG"><td><div class="fineractHeading2">Mandatory Fields for Cash based on selected report id</div></td></tr>
|
||||
<tr class=alt>
|
||||
<td>paramValue in json format</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
|
||||
<code class="method-declaration">POST https://Domain Name/api/v1/smscampaigns</code>
|
||||
<code class="method-request">POST smscampaigns
|
||||
Content-Type: application/json
|
||||
Request Body:
|
||||
{
|
||||
"campaignName": "Savings Deposit Campaign",
|
||||
"campaignType": "SMS",
|
||||
"triggerType": 3,
|
||||
"providerId": 2,
|
||||
"runReportId": 180,
|
||||
"paramValue": "{"officeId":1,"loanOfficerId":-1,"transactionId":1,"reportName":"Savings Deposit"}",
|
||||
"message": "Hello {fullName} your account is credited with {depositAmount} on {transactionDate}",
|
||||
}
|
||||
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"resourceId": 1
|
||||
}
|
||||
</code>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="smscampaigns_list" name="smscampaigns_list" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>List SMS Campaigns</h4>
|
||||
<table class=matrixHeading>
|
||||
<tr class="matrixHeadingBG"><td><div class="fineractHeading2">Mandatory Fields</div></td></tr>
|
||||
<tr class=alt>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>Example Requests:</p>
|
||||
<div class=apiClick>smscampaigns</div>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
|
||||
<code class="method-declaration">GET https://Domain Name/api/v1/smscampaigns</code>
|
||||
<code class="method-response">
|
||||
|
||||
[{
|
||||
"id": 1,
|
||||
"campaignName": "Savings Deposit Campaign"
|
||||
"campaignType": "SMS",
|
||||
"triggerType": 3,
|
||||
"providerId": 2,
|
||||
"runReportId": 180,
|
||||
"reportName" : "Savings Deposit",
|
||||
"paramValue": "{"officeId":1,"loanOfficerId":-1,"transactionId":1,"reportName":"Savings Deposit"}",
|
||||
"message": "Hello {fullName} your account is credited with {depositAmount} on {transactionDate}",
|
||||
"status" : { "id":"","code":"","value":""}
|
||||
|
||||
}]
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="smscampaigns_retrieve" name="smscampaigns_retrieve" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>Retrieve a Share Product</h4>
|
||||
<p>Example Requests: </p>
|
||||
<div class=apiClick>smscampaigns/1</div>
|
||||
<br><br>
|
||||
<div class=apiClick>smscampaigns/1?template=true</div>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">GET https://Domain Name/api/v1/smscampaigns/1</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"id": 1,
|
||||
"campaignName": "Savings Deposit Campaign"
|
||||
"campaignType": "SMS",
|
||||
"triggerType": 3,
|
||||
"providerId": 2,
|
||||
"runReportId": 180,
|
||||
"reportName" : "Savings Deposit",
|
||||
"paramValue": "{"officeId":1,"loanOfficerId":-1,"transactionId":1,"reportName":"Savings Deposit"}",
|
||||
"message": "Hello {fullName} your account is credited with {depositAmount} on {transactionDate}",
|
||||
"status" : { "id":"","code":"","value":""}
|
||||
}
|
||||
<B>In case of Scheduled Campaign</B>
|
||||
{
|
||||
"id": 1,
|
||||
"campaignName": "Savings Deposit Campaign"
|
||||
"campaignType": "SMS",
|
||||
"triggerType": 3,
|
||||
"providerId": 2,
|
||||
"runReportId": 180,
|
||||
"reportName" : "Savings Deposit",
|
||||
"paramValue": "{"officeId":1,"loanOfficerId":-1,"transactionId":1,"reportName":"Savings Deposit"}",
|
||||
"message": "Hello {fullName} your account is credited with {depositAmount} on {transactionDate}",
|
||||
"status" : { "id":"","code":"","value":""},
|
||||
"nextTriggerDate": "22 Jan 2017",
|
||||
"lastTriggerDate": "22 Jan 2016",
|
||||
"recurrenceStartDate":"22 Jan 2016",
|
||||
"recurrence": "YEARLY"
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="smscampaigns_update" name="smscampaigns_update" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>Update a Campaign</h4>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">PUT https://Domain Name/api/v1/smscampaigns/{campaignId}</code>
|
||||
<code class="method-request">POST smscampaigns/1
|
||||
Content-Type: application/json
|
||||
Request Body:
|
||||
{
|
||||
"message": "Hello your savings account {savingsAccountNo} debited with {withdrawAmount}"
|
||||
|
||||
}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"resourceId": 1,
|
||||
"changes": {
|
||||
"message": "Hello your savings account {savingsAccountNo} debited with {withdrawAmount}"
|
||||
}
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="smscampaigns_delete" name="smscampaigns_delete" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>Delete a SMS Campaign</h4>
|
||||
<p>
|
||||
<b>Note:</b> Only closed SMS Campaigns can be
|
||||
deleted
|
||||
</p>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
DELETE https://DomainName/api/v1/smscampaigns/{campaignId}
|
||||
</code>
|
||||
<code class="method-request">
|
||||
DELETE smscampaigns/1
|
||||
Content-Type: application/json
|
||||
No Request Body:
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"resourceId": 1,
|
||||
"changes": {}
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="smscampaigns_activate" name="smscampaigns_activate" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h2>Activates SMS Campaign</h2>
|
||||
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">POST https://Domain Name/api/v1/smscampaigns/{campaignId}?command=activate</code>
|
||||
<code class="method-request">POST smscampaigns/1?command=activate
|
||||
Content-Type: application/json
|
||||
Request Body:
|
||||
{
|
||||
"activationDate":"01 May 2016",
|
||||
"locale":"en",
|
||||
"dateFormat":"dd MMMM yyyy"
|
||||
}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
|
||||
"resourceId": 1,
|
||||
"changes": {
|
||||
"status": {
|
||||
"id": 300,
|
||||
"code": "smsCampaignStatus.active",
|
||||
"value": "Activated",
|
||||
},
|
||||
"locale": "en",
|
||||
"dateFormat": "dd MMMM yyyy",
|
||||
"activationDate": "01 May 2016"
|
||||
}
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="smscampaigns_close" name="smscampaigns_close" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h2>Deactivates SMS Campaign</h2>
|
||||
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">POST https://Domain Name/api/v1/smscampaigns/{campaignId}?command=close</code>
|
||||
<code class="method-request">POST smscampaigns/1?command=close
|
||||
Content-Type: application/json
|
||||
Request Body:
|
||||
{
|
||||
"closureDate":"01 May 2016",
|
||||
"locale":"en",
|
||||
"dateFormat":"dd MMMM yyyy"
|
||||
}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"resourceId": 1,
|
||||
"changes": {
|
||||
"status": {
|
||||
"id": 600,
|
||||
"code": "smsCampaignStatus.closed",
|
||||
"value": "Activated",
|
||||
},
|
||||
"locale": "en",
|
||||
"dateFormat": "dd MMMM yyyy",
|
||||
"closureDate": "01 May 2016"
|
||||
}
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="smscampaigns_reactivate" name="smscampaigns_reactivate" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h2>Reactivates SMS Campaign</h2>
|
||||
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">POST https://Domain Name/api/v1/smscampaigns/{campaignId}?command=reactivate</code>
|
||||
<code class="method-request">POST smscampaigns/1?command=reactivate
|
||||
Content-Type: application/json
|
||||
Request Body:
|
||||
{
|
||||
"activationDate":"01 May 2016",
|
||||
"locale":"en",
|
||||
"dateFormat":"dd MMMM yyyy"
|
||||
}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
|
||||
"resourceId": 1,
|
||||
"changes": {
|
||||
"status": {
|
||||
"id": 300,
|
||||
"code": "smsCampaignStatus.active",
|
||||
"value": "Activated",
|
||||
},
|
||||
"locale": "en",
|
||||
"dateFormat": "dd MMMM yyyy",
|
||||
"activationDate": "01 May 2016"
|
||||
}
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="shareproducts_create" name="shareproducts_create" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>Create a Share Product</h4>
|
||||
|
||||
+47
@@ -2803,4 +2803,51 @@ public class CommandWrapperBuilder {
|
||||
this.href = "/reportmailingjobs/" + entityId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder createSmsCampaign() {
|
||||
this.actionName = "CREATE";
|
||||
this.entityName = "SMSCAMPAIGN";
|
||||
this.entityId = null;
|
||||
this.href = "/smscampaign";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder updateSmsCampaign(final Long resourceId) {
|
||||
this.actionName = "UPDATE";
|
||||
this.entityName = "SMSCAMPAIGN";
|
||||
this.entityId = resourceId;
|
||||
this.href = "/smscampaign/"+resourceId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder activateSmsCampaign(final Long resourceId) {
|
||||
this.actionName = "ACTIVATE";
|
||||
this.entityName = "SMSCAMPAIGN";
|
||||
this.entityId = resourceId;
|
||||
this.href = "/smscampaign/"+resourceId + "?command=activate";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder closeSmsCampaign(final Long resourceId) {
|
||||
this.actionName = "CLOSE";
|
||||
this.entityName = "SMSCAMPAIGN";
|
||||
this.entityId = resourceId;
|
||||
this.href = "/smscampaign/"+resourceId + "?command=close";
|
||||
return this;
|
||||
}
|
||||
public CommandWrapperBuilder reactivateSmsCampaign(final Long resourceId) {
|
||||
this.actionName = "REACTIVATE";
|
||||
this.entityName = "SMSCAMPAIGN";
|
||||
this.entityId = resourceId;
|
||||
this.href = "/smscampaign/"+resourceId + "?command=reactivate";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder deleteSmsCampaign(final Long resourceId) {
|
||||
this.actionName = "DELETE";
|
||||
this.entityName = "SMSCAMPAIGN";
|
||||
this.entityId = resourceId;
|
||||
this.href = "/smscampaign/"+resourceId;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 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.constants;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
|
||||
public enum CampaignType {
|
||||
INVALID(0, "campaignType.invalid"), SMS(1, "campaignType.sms");
|
||||
|
||||
private Integer value;
|
||||
private String code;
|
||||
|
||||
private CampaignType(Integer value, String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public static CampaignType fromInt(final Integer typeValue) {
|
||||
CampaignType type = null;
|
||||
switch (typeValue) {
|
||||
case 0:
|
||||
type = INVALID;
|
||||
break;
|
||||
case 1:
|
||||
type = SMS;
|
||||
break;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
public static EnumOptionData campaignType(final Integer campaignTypeId) {
|
||||
return campaignType(CampaignType.fromInt(campaignTypeId));
|
||||
}
|
||||
|
||||
public static EnumOptionData campaignType(final CampaignType campaignType) {
|
||||
EnumOptionData optionData = new EnumOptionData(CampaignType.INVALID.getValue().longValue(), CampaignType.INVALID.getCode(),
|
||||
"Invalid");
|
||||
switch (campaignType) {
|
||||
case INVALID:
|
||||
optionData = new EnumOptionData(CampaignType.INVALID.getValue().longValue(), CampaignType.INVALID.getCode(), "Invalid");
|
||||
break;
|
||||
case SMS:
|
||||
optionData = new EnumOptionData(CampaignType.SMS.getValue().longValue(), CampaignType.SMS.getCode(), "SMS");
|
||||
break;
|
||||
}
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public boolean isSms() {
|
||||
return this.value.equals(CampaignType.SMS.getValue());
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 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.helper;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignConstants;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.data.MessageGatewayConfigurationData;
|
||||
import org.apache.fineract.infrastructure.configuration.service.ExternalServicesPropertiesReadPlatformService;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class SmsConfigUtils {
|
||||
|
||||
@Autowired
|
||||
private ExternalServicesPropertiesReadPlatformService propertiesReadPlatformService;
|
||||
|
||||
//This method will return uri and HttpEntry objects with keys as uri and entity
|
||||
public Map<String, Object> getMessageGateWayRequestURI(final String apiEndPoint, String apiQueueResourceDatas) {
|
||||
Map<String, Object> httpRequestdetails = new HashMap<>();
|
||||
MessageGatewayConfigurationData messageGatewayConfigurationData = this.propertiesReadPlatformService.getSMSGateway();
|
||||
final FineractPlatformTenant tenant = ThreadLocalContextUtil.getTenant();
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.add(SmsCampaignConstants.FINERACT_PLATFORM_TENANT_ID, tenant.getTenantIdentifier());
|
||||
headers.add(SmsCampaignConstants.FINERACT_TENANT_APP_KEY, messageGatewayConfigurationData.getTenantAppKey());
|
||||
StringBuilder pathBuilder = new StringBuilder();
|
||||
String endPoint = (messageGatewayConfigurationData.getEndPoint() == null || messageGatewayConfigurationData.getEndPoint().equals(
|
||||
"/")) ? "" : messageGatewayConfigurationData.getEndPoint();
|
||||
pathBuilder = (messageGatewayConfigurationData.getEndPoint() == null || messageGatewayConfigurationData.getEndPoint().equals("/")) ? pathBuilder
|
||||
.append("{apiEndPoint}") : pathBuilder.append("{endPoint}/{apiEndPoint}");
|
||||
// pathBuilder.append("{endPoint}/{apiEndPoint}") ;
|
||||
UriBuilder builder = UriBuilder.fromPath(pathBuilder.toString()).host(messageGatewayConfigurationData.getHostName()).scheme("http")
|
||||
.port(messageGatewayConfigurationData.getPortNumber());
|
||||
URI uri = (messageGatewayConfigurationData.getEndPoint() == null || messageGatewayConfigurationData.getEndPoint().equals("/")) ? builder
|
||||
.build(apiEndPoint) : builder.build(endPoint, apiEndPoint);
|
||||
HttpEntity<?> entity = null;
|
||||
if (apiQueueResourceDatas != null) {
|
||||
entity = new HttpEntity<>(apiQueueResourceDatas, headers);
|
||||
} else {
|
||||
entity = new HttpEntity<>(headers);
|
||||
}
|
||||
|
||||
httpRequestdetails.put("uri", uri);
|
||||
httpRequestdetails.put("entity", entity);
|
||||
|
||||
return httpRequestdetails;
|
||||
}
|
||||
|
||||
}
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* 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.api;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.fineract.commands.domain.CommandWrapper;
|
||||
import org.apache.fineract.commands.service.CommandWrapperBuilder;
|
||||
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.campaigns.constants.CampaignType;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignConstants;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.data.CampaignPreviewData;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.data.SmsCampaignData;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.service.SmsCampaignReadPlatformService;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.service.SmsCampaignWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonQuery;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
@Path("/smscampaigns")
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class SmsCampaignApiResource {
|
||||
|
||||
private final PlatformSecurityContext platformSecurityContext;
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
private final DefaultToApiJsonSerializer<SmsCampaignData> toApiJsonSerializer;
|
||||
private final SmsCampaignReadPlatformService smsCampaignReadPlatformService;
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
private final FromJsonHelper fromJsonHelper;
|
||||
private final DefaultToApiJsonSerializer<CampaignPreviewData> previewCampaignMessageDefaultToApiJsonSerializer;
|
||||
private final SmsCampaignWritePlatformService smsCampaignWritePlatformService;
|
||||
|
||||
private final String resourceNameForPermissions = "SMS_CAMPAIGN";
|
||||
private final PlatformSecurityContext context;
|
||||
|
||||
@Autowired
|
||||
public SmsCampaignApiResource(final PlatformSecurityContext platformSecurityContext,
|
||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
||||
final DefaultToApiJsonSerializer<SmsCampaignData> toApiJsonSerializer,
|
||||
final SmsCampaignReadPlatformService smsCampaignReadPlatformService, final ApiRequestParameterHelper apiRequestParameterHelper,
|
||||
final FromJsonHelper fromJsonHelper,
|
||||
final DefaultToApiJsonSerializer<CampaignPreviewData> previewCampaignMessageDefaultToApiJsonSerializer,
|
||||
final PlatformSecurityContext context, final SmsCampaignWritePlatformService smsCampaignWritePlatformService) {
|
||||
this.platformSecurityContext = platformSecurityContext;
|
||||
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
this.smsCampaignReadPlatformService = smsCampaignReadPlatformService;
|
||||
this.apiRequestParameterHelper = apiRequestParameterHelper;
|
||||
this.fromJsonHelper = fromJsonHelper;
|
||||
this.previewCampaignMessageDefaultToApiJsonSerializer = previewCampaignMessageDefaultToApiJsonSerializer;
|
||||
this.context = context;
|
||||
this.smsCampaignWritePlatformService = smsCampaignWritePlatformService;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("template")
|
||||
public String template(@Context final UriInfo uriInfo) {
|
||||
this.platformSecurityContext.authenticatedUser().validateHasReadPermission(SmsCampaignConstants.RESOURCE_NAME);
|
||||
final SmsCampaignData smsCampaignData = this.smsCampaignReadPlatformService.retrieveTemplate(CampaignType.SMS.name());
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, smsCampaignData);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String createCampaign(final String apiRequestBodyAsJson) {
|
||||
this.platformSecurityContext.authenticatedUser();
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().createSmsCampaign().withJson(apiRequestBodyAsJson).build();
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{resourceId}")
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveCampaign(@PathParam("resourceId") final Long resourceId, @Context final UriInfo uriInfo) {
|
||||
this.platformSecurityContext.authenticatedUser().validateHasReadPermission(SmsCampaignConstants.RESOURCE_NAME);
|
||||
SmsCampaignData smsCampaignData = this.smsCampaignReadPlatformService.retrieveOne(resourceId);
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, smsCampaignData);
|
||||
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveAllCampaigns(@Context final UriInfo uriInfo) {
|
||||
this.platformSecurityContext.authenticatedUser().validateHasReadPermission(SmsCampaignConstants.RESOURCE_NAME);
|
||||
Collection<SmsCampaignData> smsCampaignDataCollection = this.smsCampaignReadPlatformService.retrieveAll();
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, smsCampaignDataCollection);
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("{campaignId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String updateCampaign(@PathParam("campaignId") final Long campaignId, final String apiRequestBodyAsJson) {
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateSmsCampaign(campaignId).withJson(apiRequestBodyAsJson)
|
||||
.build();
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("{campaignId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String handleCommands(@PathParam("campaignId") final Long campaignId, @QueryParam("command") final String commandParam,
|
||||
final String apiRequestBodyAsJson) {
|
||||
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
|
||||
CommandProcessingResult result = null;
|
||||
CommandWrapper commandRequest = null;
|
||||
if (is(commandParam, "activate")) {
|
||||
commandRequest = builder.activateSmsCampaign(campaignId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "close")) {
|
||||
commandRequest = builder.closeSmsCampaign(campaignId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "reactivate")) {
|
||||
commandRequest = builder.reactivateSmsCampaign(campaignId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
}
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("preview")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String preview(final String apiRequestBodyAsJson, @Context final UriInfo uriInfo) {
|
||||
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
|
||||
|
||||
CampaignPreviewData campaignMessage = null;
|
||||
final JsonElement parsedQuery = this.fromJsonHelper.parse(apiRequestBodyAsJson);
|
||||
final JsonQuery query = JsonQuery.from(apiRequestBodyAsJson, parsedQuery, this.fromJsonHelper);
|
||||
campaignMessage = this.smsCampaignWritePlatformService.previewMessage(query);
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.previewCampaignMessageDefaultToApiJsonSerializer.serialize(settings, campaignMessage, new HashSet<String>());
|
||||
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{campaignId}")
|
||||
public String delete(@PathParam("campaignId") final Long campaignId) {
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteSmsCampaign(campaignId).build();
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
private boolean is(final String commandParam, final String commandValue) {
|
||||
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
|
||||
}
|
||||
}
|
||||
+43
@@ -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.constants;
|
||||
|
||||
public interface SmsCampaignConstants {
|
||||
|
||||
String SMS_CAMPAIGN_NAME = "sms";
|
||||
|
||||
String RESOURCE_NAME = "SMSCAMPAIGN";
|
||||
|
||||
String SMS_BRIDGE = "sms_bridge";
|
||||
|
||||
String SMS = "sms";
|
||||
|
||||
String FINERACT_PLATFORM_TENANT_ID = "Fineract-Platform-TenantId";
|
||||
|
||||
String FINERACT_TENANT_APP_KEY = "Fineract-Tenant-App-Key";
|
||||
|
||||
//Supported Triggered Campaigns
|
||||
|
||||
String LOAN_REJECT = "Loan Rejected" ;
|
||||
|
||||
String LOAN_APPROVED = "Loan Approved" ;
|
||||
|
||||
String LOAN_REPAYMENT = "Loan Repayment" ;
|
||||
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* 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.constants;
|
||||
|
||||
import java.time.Month;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.fineract.infrastructure.campaigns.constants.CampaignType;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
|
||||
|
||||
public class SmsCampaignEnumerations {
|
||||
|
||||
|
||||
public static EnumOptionData smscampaignTriggerType(final SmsCampaignTriggerType type) {
|
||||
EnumOptionData optionData = new EnumOptionData(SmsCampaignTriggerType.INVALID.getValue().longValue(),
|
||||
SmsCampaignTriggerType.INVALID.getCode(), "Invalid");
|
||||
switch (type) {
|
||||
case INVALID:
|
||||
break;
|
||||
case DIRECT:
|
||||
optionData = new EnumOptionData(SmsCampaignTriggerType.DIRECT.getValue().longValue(),
|
||||
SmsCampaignTriggerType.DIRECT.getCode(), "Direct");
|
||||
break;
|
||||
case SCHEDULE:
|
||||
optionData = new EnumOptionData(SmsCampaignTriggerType.SCHEDULE.getValue().longValue(),
|
||||
SmsCampaignTriggerType.SCHEDULE.getCode(), "Scheduled");
|
||||
break;
|
||||
case TRIGGERED:
|
||||
optionData = new EnumOptionData(SmsCampaignTriggerType.TRIGGERED.getValue().longValue(),
|
||||
SmsCampaignTriggerType.TRIGGERED.getCode(), "Triggered");
|
||||
break;
|
||||
}
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public static EnumOptionData smscampaignType(final CampaignType type) {
|
||||
EnumOptionData optionData = new EnumOptionData(CampaignType.INVALID.getValue().longValue(), CampaignType.INVALID.getCode(),
|
||||
"Invalid");
|
||||
switch (type) {
|
||||
case INVALID:
|
||||
break;
|
||||
case SMS:
|
||||
optionData = new EnumOptionData(CampaignType.SMS.getValue().longValue(), CampaignType.SMS.getCode(), "SMS");
|
||||
break;
|
||||
}
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public static EnumOptionData calendarMonthType(final Month entityType) {
|
||||
final EnumOptionData optionData = new EnumOptionData(new Long(entityType.getValue()), entityType.name(), entityType.name());
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public static List<EnumOptionData> calendarMonthType() {
|
||||
final List<EnumOptionData> optionDatas = new ArrayList<>();
|
||||
for (final Month monthType : Month.values()) {
|
||||
if (Month.DECEMBER.compareTo(monthType) != 0) {
|
||||
optionDatas.add(calendarMonthType(monthType));
|
||||
}
|
||||
}
|
||||
return optionDatas;
|
||||
}
|
||||
|
||||
public static List<EnumOptionData> calendarPeriodFrequencyTypes(final PeriodFrequencyType[] periodFrequencyTypes) {
|
||||
final List<EnumOptionData> optionDatas = new ArrayList<>();
|
||||
for (final PeriodFrequencyType periodFrequencyType : periodFrequencyTypes) {
|
||||
final EnumOptionData optionData = new EnumOptionData(periodFrequencyType.getValue().longValue(), periodFrequencyType.getCode(),
|
||||
periodFrequencyType.toString());
|
||||
optionDatas.add(optionData);
|
||||
}
|
||||
return optionDatas;
|
||||
}
|
||||
}
|
||||
+72
@@ -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.constants;
|
||||
|
||||
public enum SmsCampaignStatus {
|
||||
|
||||
INVALID(-1, "smsCampaignStatus.invalid"), //
|
||||
PENDING(100, "smsCampaignStatus.pending"), //
|
||||
ACTIVE(300, "smsCampaignStatus.active"), //
|
||||
CLOSED(600, "smsCampaignStatus.closed");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
private SmsCampaignStatus(Integer value, String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public static SmsCampaignStatus fromInt(final Integer statusValue) {
|
||||
|
||||
SmsCampaignStatus enumeration = SmsCampaignStatus.INVALID;
|
||||
switch (statusValue) {
|
||||
case 100:
|
||||
enumeration = SmsCampaignStatus.PENDING;
|
||||
break;
|
||||
case 300:
|
||||
enumeration = SmsCampaignStatus.ACTIVE;
|
||||
break;
|
||||
case 600:
|
||||
enumeration = SmsCampaignStatus.CLOSED;
|
||||
break;
|
||||
}
|
||||
return enumeration;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return this.value.equals(SmsCampaignStatus.ACTIVE.getValue());
|
||||
}
|
||||
|
||||
public boolean isPending() {
|
||||
return this.value.equals(SmsCampaignStatus.PENDING.getValue());
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return this.value.equals(SmsCampaignStatus.CLOSED.getValue());
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* 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.constants;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
|
||||
public enum SmsCampaignTriggerType {
|
||||
INVALID(-1, "triggerType.invalid"), DIRECT(1, "triggerType.direct"), SCHEDULE(2, "triggerType.schedule"), TRIGGERED(3,
|
||||
"triggerType.triggered");
|
||||
|
||||
private Integer value;
|
||||
private String code;
|
||||
|
||||
private SmsCampaignTriggerType(Integer value, String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public static SmsCampaignTriggerType fromInt(final Integer typeValue) {
|
||||
SmsCampaignTriggerType type = null;
|
||||
switch (typeValue) {
|
||||
case 1:
|
||||
type = DIRECT;
|
||||
break;
|
||||
case 2:
|
||||
type = SCHEDULE;
|
||||
break;
|
||||
case 3:
|
||||
type = TRIGGERED;
|
||||
break;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
public static EnumOptionData triggerType(final Integer triggerTypeId) {
|
||||
return triggerType(SmsCampaignTriggerType.fromInt(triggerTypeId));
|
||||
}
|
||||
|
||||
public static EnumOptionData triggerType(final SmsCampaignTriggerType triggerType) {
|
||||
EnumOptionData optionData = new EnumOptionData(SmsCampaignTriggerType.INVALID.getValue().longValue(),
|
||||
SmsCampaignTriggerType.INVALID.getCode(), "Invalid");
|
||||
switch (triggerType) {
|
||||
case INVALID:
|
||||
optionData = new EnumOptionData(SmsCampaignTriggerType.INVALID.getValue().longValue(),
|
||||
SmsCampaignTriggerType.INVALID.getCode(), "Invalid");
|
||||
break;
|
||||
case DIRECT:
|
||||
optionData = new EnumOptionData(SmsCampaignTriggerType.DIRECT.getValue().longValue(),
|
||||
SmsCampaignTriggerType.DIRECT.getCode(), "Direct");
|
||||
break;
|
||||
case SCHEDULE:
|
||||
optionData = new EnumOptionData(SmsCampaignTriggerType.SCHEDULE.getValue().longValue(),
|
||||
SmsCampaignTriggerType.SCHEDULE.getCode(), "Schedule");
|
||||
break;
|
||||
case TRIGGERED:
|
||||
optionData = new EnumOptionData(SmsCampaignTriggerType.TRIGGERED.getValue().longValue(),
|
||||
SmsCampaignTriggerType.TRIGGERED.getCode(), "Triggered");
|
||||
break;
|
||||
}
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public boolean isDirect() {
|
||||
return this.value.equals(SmsCampaignTriggerType.DIRECT.getValue());
|
||||
}
|
||||
|
||||
public boolean isSchedule() {
|
||||
return this.value.equals(SmsCampaignTriggerType.SCHEDULE.getValue());
|
||||
}
|
||||
|
||||
public boolean isTriggered() {
|
||||
return this.value.equals(SmsCampaignTriggerType.TRIGGERED.getValue());
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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 CampaignPreviewData {
|
||||
|
||||
private final String campaignMessage;
|
||||
|
||||
private final Integer totalNumberOfMessages;
|
||||
|
||||
public CampaignPreviewData(String campaignMessage, Integer totalNumberOfMessages) {
|
||||
this.campaignMessage = campaignMessage;
|
||||
this.totalNumberOfMessages = totalNumberOfMessages;
|
||||
}
|
||||
|
||||
public String getCampaignMessage() {
|
||||
return campaignMessage;
|
||||
}
|
||||
|
||||
public Integer getTotalNumberOfMessages() {
|
||||
return totalNumberOfMessages;
|
||||
}
|
||||
}
|
||||
+298
@@ -0,0 +1,298 @@
|
||||
/**
|
||||
* 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.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
|
||||
public final class CampaignTriggerWithSubTypes {
|
||||
|
||||
public enum ActualCampaignTriggerType {
|
||||
INVALID(0, "campaignTriggerType.invalid"), //
|
||||
LOAN(1, "campaignTriggerType.loan"), //
|
||||
SAVING(2, "campaignTriggerType.saving"), //
|
||||
CLIENT(3, "campaignTriggerType.client");
|
||||
|
||||
private Integer value;
|
||||
private String code;
|
||||
|
||||
private ActualCampaignTriggerType(Integer value, String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public static ActualCampaignTriggerType fromInt(final Integer typeValue) {
|
||||
ActualCampaignTriggerType type = ActualCampaignTriggerType.INVALID;
|
||||
switch (typeValue) {
|
||||
case 1:
|
||||
type = LOAN;
|
||||
break;
|
||||
case 2:
|
||||
type = SAVING;
|
||||
break;
|
||||
case 3:
|
||||
type = CLIENT;
|
||||
break;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public static EnumOptionData toEnumOptionData(final ActualCampaignTriggerType triggerType) {
|
||||
final EnumOptionData optionData = new EnumOptionData(new Long(triggerType.getValue()), triggerType.getCode(), triggerType.name());
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public static EnumOptionData toEnumOptionData(final Integer triggerTypeValue) {
|
||||
ActualCampaignTriggerType actualCampaignTriggerType = ActualCampaignTriggerType.fromInt(triggerTypeValue);
|
||||
final EnumOptionData optionData = new EnumOptionData(new Long(actualCampaignTriggerType.getValue()),
|
||||
actualCampaignTriggerType.getCode(), actualCampaignTriggerType.name());
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public boolean isInvalid() {
|
||||
return this.value.equals(ActualCampaignTriggerType.INVALID.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public enum CampaignTriggerSubType {
|
||||
INVALID(0, ActualCampaignTriggerType.INVALID, "campaignTriggerSubType.invalid"), //
|
||||
|
||||
DISBURSE(101, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.disburse"), //
|
||||
REPAYMENT(102, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.repayment"), //
|
||||
UNDO_DISBURSAL(103, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.undodisbursal"), //
|
||||
WRITE_OFF(104, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.writeoff"), //
|
||||
ADJUST(105, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.adjust"), //
|
||||
UNDO_WRITE_OFF(106, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.undowriteoff"), //
|
||||
FORECLOSURE(107, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.foreclosure"), //
|
||||
APPROVED(108, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.approved"), //
|
||||
WAIVE_INTEREST(109, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.waive.interest"), //
|
||||
CLOSE(110, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.close"), //
|
||||
CLOSE_AS_RESCHEDULE(111, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.close.as.rescheduled"), //
|
||||
ADD_CHARGE(112, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.add.charge"), //
|
||||
UPDATE_CHARGE(113, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.update.charge"), //
|
||||
WAIVE_CHARGE(114, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.waive.charge"), //
|
||||
DELETE_CHARGE(115, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.delete.charge"), //
|
||||
CHARGE_PAYMENT(116, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.charge.payment"), //
|
||||
INITIATE_TRANSFER(117, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.initiate.transfer"), //
|
||||
ACCEPT_TRANSFER(118, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.accept.transfer"), //
|
||||
WITHDRAW_TRANSFER(119, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.withdraw.transfer"), //
|
||||
REJECT_TRANSFER(120, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.reject.transfer"), //
|
||||
REASSIGN_OFFICER(121, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.reassign.officer"), //
|
||||
REMOVE_OFFICER(122, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.reassign.officer"), //
|
||||
APPLY_OVERDUE_CHARGE(123, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.reassign.officer"), //
|
||||
INTEREST_RECALCULATION(124, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.reassign.officer"), //
|
||||
REFUND(125, ActualCampaignTriggerType.LOAN, "campaignTriggerSubType.reassign.officer"), //
|
||||
|
||||
SAVINGS_DEPOSIT(201, ActualCampaignTriggerType.SAVING, "campaignTriggerSubType.deposit"), //
|
||||
SAVINGS_WITHDRAWAL(202, ActualCampaignTriggerType.SAVING, "campaignTriggerSubType.withdrawal"), //
|
||||
SAVINGS_ACTIVATE(203, ActualCampaignTriggerType.SAVING, "campaignTriggerSubType.savings.activate"), //
|
||||
SAVINGS_ADJUST_TRANSACTION(204, ActualCampaignTriggerType.SAVING, "campaignTriggerSubType.savings.adjust"), //
|
||||
SAVINGS_APPLY_ANNUAL_FEE(205, ActualCampaignTriggerType.SAVING, "campaignTriggerSubType.savings.apply.annual.fee"), //
|
||||
SAVINGS_CALCULATE_INTEREST(206, ActualCampaignTriggerType.SAVING, "campaignTriggerSubType.savings.calclulate.interest"), //
|
||||
SAVINGS_CLOSE(207, ActualCampaignTriggerType.SAVING, "campaignTriggerSubType.savings.close"), //
|
||||
SAVINGS_POST_INTEREST(208, ActualCampaignTriggerType.SAVING, "campaignTriggerSubType.savings.post"), //
|
||||
SAVINGS_REJECT(209, ActualCampaignTriggerType.SAVING, "campaignTriggerSubType.savings.reject"), //
|
||||
SAVINGS_UNDO(210, ActualCampaignTriggerType.SAVING, "campaignTriggerSubType.savings.undo"), //
|
||||
SAVINGS_ADD_CHARGE(211, ActualCampaignTriggerType.SAVING, "campaignTriggerSubType.savings.add.charge"), //
|
||||
SAVINGS_WAIVE_CHARGE(212, ActualCampaignTriggerType.SAVING, "campaignTriggerSubType.savings.waive.charge"), //
|
||||
SAVINGS_PAY_CHARGE(213, ActualCampaignTriggerType.SAVING, "campaignTriggerSubType.savings.pay.charge"), //
|
||||
|
||||
CLIENTS_ACTIVATE(301, ActualCampaignTriggerType.CLIENT, "campaignTriggerSubType.activate"), //
|
||||
CLIENTS_CLOSE(302, ActualCampaignTriggerType.CLIENT, "campaignTriggerSubType.close"), //
|
||||
CLIENTS_ACCEPT_TRANSFER(303, ActualCampaignTriggerType.CLIENT, "campaignTriggerSubType.accept.transfer"), //
|
||||
CLIENTS_ASSIGN_STAFF(304, ActualCampaignTriggerType.CLIENT, "campaignTriggerSubType.assign.staff"), //
|
||||
CLIENTS_CREATE(305, ActualCampaignTriggerType.CLIENT, "campaignTriggerSubType.create"), //
|
||||
CLIENTS_DELETE(306, ActualCampaignTriggerType.CLIENT, "campaignTriggerSubType.delete"), //
|
||||
CLIENTS_PROPOSE_TRANSFER(307, ActualCampaignTriggerType.CLIENT, "campaignTriggerSubType.propose.transfer"), //
|
||||
CLIENTS_REACTIVATE(308, ActualCampaignTriggerType.CLIENT, "campaignTriggerSubType.reactivate"), //
|
||||
CLIENTS_REJECT(309, ActualCampaignTriggerType.CLIENT, "campaignTriggerSubType.reject"), //
|
||||
CLIENTS_REJECT_TRANSFER(310, ActualCampaignTriggerType.CLIENT, "campaignTriggerSubType.reject.transfer"), //
|
||||
CLIENTS_WITHDRAW(311, ActualCampaignTriggerType.CLIENT, "campaignTriggerSubType.withdraw"), //
|
||||
CLIENTS_WITHDRAW_TRANSFER(312, ActualCampaignTriggerType.CLIENT, "campaignTriggerSubType.withdraw.transfer");
|
||||
|
||||
private Integer id;
|
||||
private ActualCampaignTriggerType type;
|
||||
private String code;
|
||||
|
||||
private CampaignTriggerSubType(Integer id, ActualCampaignTriggerType type, String code) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public static CampaignTriggerSubType fromInt(final Integer subTypeValue) {
|
||||
CampaignTriggerSubType subType = CampaignTriggerSubType.INVALID;
|
||||
switch (subTypeValue) {
|
||||
case 101:
|
||||
subType = DISBURSE;
|
||||
break;
|
||||
case 102:
|
||||
subType = REPAYMENT;
|
||||
break;
|
||||
case 103:
|
||||
subType = ADJUST;
|
||||
break;
|
||||
case 104:
|
||||
subType = UNDO_DISBURSAL;
|
||||
break;
|
||||
case 105:
|
||||
subType = WRITE_OFF;
|
||||
break;
|
||||
case 106:
|
||||
subType = UNDO_WRITE_OFF;
|
||||
break;
|
||||
|
||||
case 201:
|
||||
subType = SAVINGS_DEPOSIT;
|
||||
break;
|
||||
case 202:
|
||||
subType = SAVINGS_WITHDRAWAL;
|
||||
break;
|
||||
case 203:
|
||||
subType = SAVINGS_ACTIVATE;
|
||||
break;
|
||||
case 204:
|
||||
subType = SAVINGS_ADJUST_TRANSACTION;
|
||||
break;
|
||||
case 205:
|
||||
subType = SAVINGS_APPLY_ANNUAL_FEE;
|
||||
break;
|
||||
case 206:
|
||||
subType = SAVINGS_CALCULATE_INTEREST;
|
||||
break;
|
||||
case 207:
|
||||
subType = SAVINGS_CLOSE;
|
||||
break;
|
||||
case 208:
|
||||
subType = SAVINGS_POST_INTEREST;
|
||||
break;
|
||||
case 209:
|
||||
subType = SAVINGS_REJECT;
|
||||
break;
|
||||
case 210:
|
||||
subType = SAVINGS_UNDO;
|
||||
break;
|
||||
case 211:
|
||||
subType = SAVINGS_ADD_CHARGE;
|
||||
break;
|
||||
case 212:
|
||||
subType = SAVINGS_WAIVE_CHARGE;
|
||||
break;
|
||||
case 213:
|
||||
subType = SAVINGS_PAY_CHARGE;
|
||||
break;
|
||||
|
||||
case 301:
|
||||
subType = CLIENTS_ACTIVATE;
|
||||
break;
|
||||
case 302:
|
||||
subType = CLIENTS_CLOSE;
|
||||
break;
|
||||
case 303:
|
||||
subType = CLIENTS_ACCEPT_TRANSFER;
|
||||
break;
|
||||
case 304:
|
||||
subType = CLIENTS_ASSIGN_STAFF;
|
||||
break;
|
||||
case 305:
|
||||
subType = CLIENTS_CREATE;
|
||||
break;
|
||||
case 306:
|
||||
subType = CLIENTS_DELETE;
|
||||
break;
|
||||
case 307:
|
||||
subType = CLIENTS_PROPOSE_TRANSFER;
|
||||
break;
|
||||
case 308:
|
||||
subType = CLIENTS_REACTIVATE;
|
||||
break;
|
||||
case 309:
|
||||
subType = CLIENTS_REJECT;
|
||||
break;
|
||||
case 310:
|
||||
subType = CLIENTS_REJECT_TRANSFER;
|
||||
break;
|
||||
case 311:
|
||||
subType = CLIENTS_WITHDRAW;
|
||||
break;
|
||||
case 312:
|
||||
subType = CLIENTS_WITHDRAW_TRANSFER;
|
||||
break;
|
||||
}
|
||||
return subType;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public ActualCampaignTriggerType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public static EnumOptionData toEnumOptionData(final Integer triggerSubType) {
|
||||
CampaignTriggerSubType subTypeEnum = CampaignTriggerSubType.fromInt(triggerSubType);
|
||||
final EnumOptionData optionData = new EnumOptionData(new Long(subTypeEnum.getId()), subTypeEnum.getCode(), subTypeEnum.name());
|
||||
return optionData;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<EnumOptionData> addTypeSubTypeMapping(ActualCampaignTriggerType type) {
|
||||
List<EnumOptionData> subTypeList = new ArrayList<>();
|
||||
EnumOptionData optionData = null;
|
||||
for (CampaignTriggerSubType subType : CampaignTriggerSubType.values()) {
|
||||
if (subType.getType().equals(type)) {
|
||||
optionData = new EnumOptionData(subType.getId().longValue(), subType.getCode(), subType.name());
|
||||
subTypeList.add(optionData);
|
||||
}
|
||||
}
|
||||
return subTypeList;
|
||||
}
|
||||
|
||||
public static Collection<TriggerTypeWithSubTypesData> getTriggerTypeAndSubTypes() {
|
||||
final Collection<TriggerTypeWithSubTypesData> typesList = new ArrayList<>();
|
||||
EnumOptionData actualTriggerType = null;
|
||||
for (ActualCampaignTriggerType triggerType : ActualCampaignTriggerType.values()) {
|
||||
if (triggerType.isInvalid()) {
|
||||
continue;
|
||||
}
|
||||
List<EnumOptionData> subTypeList = addTypeSubTypeMapping(triggerType);
|
||||
actualTriggerType = ActualCampaignTriggerType.toEnumOptionData(triggerType);
|
||||
TriggerTypeWithSubTypesData triggerTypeWithSubTypesData = new TriggerTypeWithSubTypesData(actualTriggerType, subTypeList);
|
||||
typesList.add(triggerTypeWithSubTypesData);
|
||||
}
|
||||
return typesList;
|
||||
}
|
||||
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* 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 MessageGatewayConfigurationData {
|
||||
|
||||
private final Long id;
|
||||
private final String connectionName;
|
||||
private final String hostName;
|
||||
private final int portNumber;
|
||||
private final String endPoint;
|
||||
private final String userName;
|
||||
private final String password;
|
||||
private final boolean sslEnabled;
|
||||
private final String tenantAppKey;
|
||||
|
||||
public MessageGatewayConfigurationData(final Long id, final String connectionName, final String hostName, final int portNumber,
|
||||
final String endPoint, final String userName, final String password, final boolean sslEnabled, final String tenantAppKey) {
|
||||
this.id = id;
|
||||
this.connectionName = connectionName;
|
||||
this.hostName = hostName;
|
||||
this.portNumber = portNumber;
|
||||
this.endPoint = endPoint;
|
||||
this.userName = userName;
|
||||
this.password = password;
|
||||
this.sslEnabled = sslEnabled;
|
||||
this.tenantAppKey = tenantAppKey;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public String getConnectionName() {
|
||||
return this.connectionName;
|
||||
}
|
||||
|
||||
public String getHostName() {
|
||||
return this.hostName;
|
||||
}
|
||||
|
||||
public int getPortNumber() {
|
||||
return this.portNumber;
|
||||
}
|
||||
|
||||
public String getEndPoint() {
|
||||
return this.endPoint;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return this.userName;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
public boolean isSslEnabled() {
|
||||
return this.sslEnabled;
|
||||
}
|
||||
|
||||
public String getTenantAppKey() {
|
||||
return this.tenantAppKey;
|
||||
}
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* 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.Map;
|
||||
|
||||
public class SmsBusinessRulesData {
|
||||
|
||||
private final Long reportId;
|
||||
|
||||
private final String reportName;
|
||||
|
||||
private final String reportType;
|
||||
|
||||
private final String reportSubType;
|
||||
|
||||
private final String reportDescription;
|
||||
|
||||
private final Map<String, Object> reportParamName;
|
||||
|
||||
public SmsBusinessRulesData(final Long reportId, final String reportName, final String reportType, final String reportSubType,
|
||||
final Map<String, Object> reportParamName, final String reportDescription) {
|
||||
this.reportId = reportId;
|
||||
this.reportName = reportName;
|
||||
this.reportType = reportType;
|
||||
this.reportSubType = reportSubType;
|
||||
this.reportParamName = reportParamName;
|
||||
this.reportDescription = reportDescription;
|
||||
}
|
||||
|
||||
public static SmsBusinessRulesData instance(final Long reportId, final String reportName, final String reportType,
|
||||
final String reportSubType, final Map<String, Object> reportParamName, final String reportDescription) {
|
||||
return new SmsBusinessRulesData(reportId, reportName, reportType, reportSubType, reportParamName, reportDescription);
|
||||
}
|
||||
|
||||
public Map<String, Object> getReportParamName() {
|
||||
return reportParamName;
|
||||
}
|
||||
|
||||
public String getReportType() {
|
||||
return reportType;
|
||||
}
|
||||
|
||||
public String getReportSubType() {
|
||||
return this.reportSubType;
|
||||
}
|
||||
|
||||
public String getReportName() {
|
||||
return reportName;
|
||||
}
|
||||
|
||||
public Long getReportId() {
|
||||
return reportId;
|
||||
}
|
||||
|
||||
public String getReportDescription() {
|
||||
return reportDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
SmsBusinessRulesData that = (SmsBusinessRulesData) o;
|
||||
|
||||
if (reportId != null ? !reportId.equals(that.reportId) : that.reportId != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return reportId != null ? reportId.hashCode() : 0;
|
||||
}
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* 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.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class SmsCampaignData {
|
||||
|
||||
private Long id;
|
||||
private final String campaignName;
|
||||
private final EnumOptionData campaignType;
|
||||
private final Long runReportId;
|
||||
private final String reportName;
|
||||
private final String paramValue;
|
||||
private final EnumOptionData campaignStatus;
|
||||
private final EnumOptionData triggerType;
|
||||
private final String campaignMessage;
|
||||
private final DateTime nextTriggerDate;
|
||||
private final LocalDate lastTriggerDate;
|
||||
private final SmsCampaignTimeLine smsCampaignTimeLine;
|
||||
private final DateTime recurrenceStartDate;
|
||||
private final String recurrence;
|
||||
private final Long providerId;
|
||||
|
||||
private final Collection<SmsProviderData> smsProviderOptions;
|
||||
|
||||
private final Collection<EnumOptionData> campaignTypeOptions;
|
||||
|
||||
private final Collection<EnumOptionData> triggerTypeOptions;
|
||||
|
||||
private final Collection<SmsBusinessRulesData> businessRulesOptions;
|
||||
|
||||
private final Collection<EnumOptionData> months;
|
||||
|
||||
private final Collection<EnumOptionData> weekDays;
|
||||
|
||||
private final Collection<EnumOptionData> frequencyTypeOptions;
|
||||
|
||||
private final Collection<EnumOptionData> periodFrequencyOptions;
|
||||
|
||||
private SmsCampaignData(final Long id, final String campaignName, final EnumOptionData campaignType, final EnumOptionData triggerType,
|
||||
final Long runReportId,
|
||||
final String reportName, final String paramValue, final EnumOptionData campaignStatus,
|
||||
final String message, final DateTime nextTriggerDate, final LocalDate lastTriggerDate,
|
||||
final SmsCampaignTimeLine smsCampaignTimeLine, final DateTime recurrenceStartDate, final String recurrence,
|
||||
final Long providerId, final Collection<SmsBusinessRulesData> businessRulesOptions,
|
||||
final Collection<SmsProviderData> smsProviderOptions, final Collection<EnumOptionData> campaignTypeOptions,
|
||||
final Collection<EnumOptionData> triggerTypeOptions, final Collection<EnumOptionData> months,
|
||||
final Collection<EnumOptionData> weekDays, final Collection<EnumOptionData> frequencyTypeOptions,
|
||||
final Collection<EnumOptionData> periodFrequencyOptions) {
|
||||
this.id = id;
|
||||
this.campaignName = campaignName;
|
||||
this.campaignType = campaignType;
|
||||
this.triggerType = triggerType;
|
||||
this.runReportId = runReportId;
|
||||
this.reportName = reportName;
|
||||
this.paramValue = paramValue;
|
||||
this.campaignStatus = campaignStatus;
|
||||
this.campaignMessage = message;
|
||||
if (nextTriggerDate != null) {
|
||||
this.nextTriggerDate = nextTriggerDate;
|
||||
} else {
|
||||
this.nextTriggerDate = null;
|
||||
}
|
||||
if (lastTriggerDate != null) {
|
||||
this.lastTriggerDate = lastTriggerDate;
|
||||
} else {
|
||||
this.lastTriggerDate = null;
|
||||
}
|
||||
this.smsCampaignTimeLine = smsCampaignTimeLine;
|
||||
this.recurrenceStartDate = recurrenceStartDate;
|
||||
this.recurrence = recurrence;
|
||||
this.providerId = providerId;
|
||||
this.businessRulesOptions = businessRulesOptions;
|
||||
this.smsProviderOptions = smsProviderOptions;
|
||||
this.campaignTypeOptions = campaignTypeOptions;
|
||||
this.triggerTypeOptions = triggerTypeOptions;
|
||||
this.months = months;
|
||||
this.weekDays = weekDays;
|
||||
this.frequencyTypeOptions = frequencyTypeOptions;
|
||||
this.periodFrequencyOptions = periodFrequencyOptions;
|
||||
}
|
||||
|
||||
public static SmsCampaignData instance(final Long id, final String campaignName, final EnumOptionData campaignType,
|
||||
final EnumOptionData triggerType,
|
||||
final Long runReportId, final String reportName, final String paramValue, final EnumOptionData campaignStatus,
|
||||
final String message, final DateTime nextTriggerDate, final LocalDate lastTriggerDate,
|
||||
final SmsCampaignTimeLine smsCampaignTimeLine, final DateTime recurrenceStartDate, final String recurrence,
|
||||
final Long providerId) {
|
||||
final Collection<SmsBusinessRulesData> businessRulesOptions = null;
|
||||
final Collection<SmsProviderData> smsProviderOptions = null;
|
||||
final Collection<EnumOptionData> campaignTypeOptions = null;
|
||||
final Collection<EnumOptionData> triggerTypeOptions = null;
|
||||
final Collection<EnumOptionData> months = null;
|
||||
final Collection<EnumOptionData> weekDays = null;
|
||||
final Collection<EnumOptionData> frequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> periodFrequencyOptions = null;
|
||||
|
||||
return new SmsCampaignData(id, campaignName, campaignType, triggerType, runReportId,
|
||||
reportName, paramValue, campaignStatus, message, nextTriggerDate, lastTriggerDate, smsCampaignTimeLine,
|
||||
recurrenceStartDate, recurrence, providerId, businessRulesOptions, smsProviderOptions, campaignTypeOptions,
|
||||
triggerTypeOptions, months, weekDays, frequencyTypeOptions, periodFrequencyOptions);
|
||||
}
|
||||
|
||||
public static SmsCampaignData template(final Collection<SmsProviderData> smsProviderOptions,
|
||||
final Collection<EnumOptionData> campaignTypeOptions, final Collection<SmsBusinessRulesData> businessRulesOptions,
|
||||
final Collection<EnumOptionData> triggerTypeOptions, final Collection<EnumOptionData> months,
|
||||
final Collection<EnumOptionData> weekDays, final Collection<EnumOptionData> frequencyTypeOptions,
|
||||
final Collection<EnumOptionData> periodFrequencyOptions) {
|
||||
final Long id = null;
|
||||
final String campaignName = null;
|
||||
final EnumOptionData campaignType = null;
|
||||
final Long runReportId = null;
|
||||
final String paramValue = null;
|
||||
final EnumOptionData campaignStatus = null;
|
||||
final String message = null;
|
||||
final DateTime nextTriggerDate = null;
|
||||
final LocalDate lastTriggerDate = null;
|
||||
final SmsCampaignTimeLine smsCampaignTimeLine = null;
|
||||
final DateTime recurrenceStartDate = null;
|
||||
final String recurrence = null;
|
||||
final EnumOptionData triggerType = null;
|
||||
final String reportName = null;
|
||||
final Long providerId = null;
|
||||
return new SmsCampaignData(id, campaignName, campaignType, triggerType, runReportId,
|
||||
reportName, paramValue, campaignStatus, message, nextTriggerDate, lastTriggerDate, smsCampaignTimeLine,
|
||||
recurrenceStartDate, recurrence, providerId, businessRulesOptions, smsProviderOptions, campaignTypeOptions,
|
||||
triggerTypeOptions, months, weekDays, frequencyTypeOptions, periodFrequencyOptions);
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getCampaignName() {
|
||||
return this.campaignName;
|
||||
}
|
||||
|
||||
public EnumOptionData getCampaignType() {
|
||||
return this.campaignType;
|
||||
}
|
||||
|
||||
public Long getRunReportId() {
|
||||
return this.runReportId;
|
||||
}
|
||||
|
||||
public String getParamValue() {
|
||||
return this.paramValue;
|
||||
}
|
||||
|
||||
public EnumOptionData getCampaignStatus() {
|
||||
return this.campaignStatus;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return this.campaignMessage;
|
||||
}
|
||||
|
||||
public DateTime getNextTriggerDate() {
|
||||
return this.nextTriggerDate;
|
||||
}
|
||||
|
||||
public LocalDate getLastTriggerDate() {
|
||||
return this.lastTriggerDate;
|
||||
}
|
||||
|
||||
public String getRecurrence() {
|
||||
return this.recurrence;
|
||||
}
|
||||
|
||||
public DateTime getRecurrenceStartDate() {
|
||||
return this.recurrenceStartDate;
|
||||
}
|
||||
|
||||
public String getReportName() {
|
||||
return this.reportName;
|
||||
}
|
||||
|
||||
public Long providerId() {
|
||||
return this.providerId;
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -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;
|
||||
}
|
||||
}
|
||||
+72
@@ -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;
|
||||
}
|
||||
}
|
||||
+43
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+561
@@ -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();
|
||||
}
|
||||
}
|
||||
+35
@@ -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) ;
|
||||
}
|
||||
+55
@@ -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;
|
||||
}
|
||||
}
|
||||
+30
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+30
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+28
@@ -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); }
|
||||
}
|
||||
+29
@@ -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);
|
||||
}
|
||||
}
|
||||
+28
@@ -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);
|
||||
}
|
||||
}
|
||||
+47
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+43
@@ -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);
|
||||
}
|
||||
}
|
||||
+46
@@ -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);
|
||||
}
|
||||
}
|
||||
+45
@@ -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());
|
||||
}
|
||||
}
|
||||
+45
@@ -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);
|
||||
}
|
||||
}
|
||||
+46
@@ -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);
|
||||
}
|
||||
}
|
||||
+302
@@ -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); }
|
||||
}
|
||||
}
|
||||
+25
@@ -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 {
|
||||
}
|
||||
+537
@@ -0,0 +1,537 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidParameterException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignTriggerType;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.domain.SmsCampaign;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.domain.SmsCampaignRepository;
|
||||
import org.apache.fineract.infrastructure.sms.domain.SmsMessage;
|
||||
import org.apache.fineract.infrastructure.sms.domain.SmsMessageRepository;
|
||||
import org.apache.fineract.infrastructure.sms.scheduler.SmsMessageScheduledJobService;
|
||||
import org.apache.fineract.organisation.office.domain.Office;
|
||||
import org.apache.fineract.organisation.office.domain.OfficeRepository;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants;
|
||||
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY;
|
||||
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS;
|
||||
import org.apache.fineract.portfolio.common.service.BusinessEventListner;
|
||||
import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.portfolio.group.domain.Group;
|
||||
import org.apache.fineract.portfolio.group.domain.GroupRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.InvalidLoanTypeException;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.codehaus.jackson.type.TypeReference;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class SmsCampaignDomainServiceImpl implements SmsCampaignDomainService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SmsCampaignDomainServiceImpl.class);
|
||||
|
||||
private final SmsCampaignRepository smsCampaignRepository;
|
||||
private final SmsMessageRepository smsMessageRepository;
|
||||
private final OfficeRepository officeRepository;
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
private final SmsCampaignWritePlatformService smsCampaignWritePlatformCommandHandler;
|
||||
private final GroupRepository groupRepository;
|
||||
|
||||
private final SmsMessageScheduledJobService smsMessageScheduledJobService;
|
||||
|
||||
@Autowired
|
||||
public SmsCampaignDomainServiceImpl(final SmsCampaignRepository smsCampaignRepository, final SmsMessageRepository smsMessageRepository,
|
||||
final BusinessEventNotifierService businessEventNotifierService, final OfficeRepository officeRepository,
|
||||
final SmsCampaignWritePlatformService smsCampaignWritePlatformCommandHandler,
|
||||
final GroupRepository groupRepository,
|
||||
final SmsMessageScheduledJobService smsMessageScheduledJobService){
|
||||
this.smsCampaignRepository = smsCampaignRepository;
|
||||
this.smsMessageRepository = smsMessageRepository;
|
||||
this.businessEventNotifierService = businessEventNotifierService;
|
||||
this.officeRepository = officeRepository;
|
||||
this.smsCampaignWritePlatformCommandHandler = smsCampaignWritePlatformCommandHandler;
|
||||
this.groupRepository = groupRepository;
|
||||
this.smsMessageScheduledJobService = smsMessageScheduledJobService ;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void addListners() {
|
||||
this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_APPROVED, new SendSmsOnLoanApproved());
|
||||
this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_REJECTED, new SendSmsOnLoanRejected());
|
||||
this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.LOAN_MAKE_REPAYMENT, new SendSmsOnLoanRepayment());
|
||||
this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.CLIENTS_ACTIVATE, new ClientActivatedListener());
|
||||
this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.CLIENTS_REJECT, new ClientRejectedListener());
|
||||
this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_ACTIVATE, new SavingsAccountActivatedListener());
|
||||
this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_REJECT, new SavingsAccountRejectedListener());
|
||||
this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_DEPOSIT, new SavingsAccountTransactionListener(true));
|
||||
this.businessEventNotifierService.addBusinessEventPostListners(BUSINESS_EVENTS.SAVINGS_WITHDRAWAL, new SavingsAccountTransactionListener(false));
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void notifyRejectedLoanOwner(Loan loan) {
|
||||
ArrayList<SmsCampaign> smsCampaigns = retrieveSmsCampaigns("loan rejected");
|
||||
if(smsCampaigns.size()>0){
|
||||
for (SmsCampaign campaign:smsCampaigns){
|
||||
if(campaign.isActive()) {
|
||||
this.smsCampaignWritePlatformCommandHandler.insertDirectCampaignIntoSmsOutboundTable(loan, campaign);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyAcceptedLoanOwner(Loan loan) {
|
||||
ArrayList<SmsCampaign> smsCampaigns = retrieveSmsCampaigns("loan approved");
|
||||
|
||||
if(smsCampaigns.size()>0){
|
||||
for (SmsCampaign campaign:smsCampaigns){
|
||||
if(campaign.isActive()) {
|
||||
this.smsCampaignWritePlatformCommandHandler.insertDirectCampaignIntoSmsOutboundTable(loan, campaign);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyClientActivated(final Client client) {
|
||||
ArrayList<SmsCampaign> smsCampaigns = retrieveSmsCampaigns("client activated");
|
||||
if(smsCampaigns.size()>0){
|
||||
for (SmsCampaign campaign:smsCampaigns){
|
||||
if(campaign.isActive()) {
|
||||
this.smsCampaignWritePlatformCommandHandler.insertDirectCampaignIntoSmsOutboundTable(client, campaign);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void notifyClientRejected(final Client client) {
|
||||
ArrayList<SmsCampaign> smsCampaigns = retrieveSmsCampaigns("client rejected");
|
||||
if(smsCampaigns.size()>0){
|
||||
for (SmsCampaign campaign:smsCampaigns){
|
||||
if(campaign.isActive()) {
|
||||
this.smsCampaignWritePlatformCommandHandler.insertDirectCampaignIntoSmsOutboundTable(client, campaign);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void notifySavingsAccountActivated(final SavingsAccount savingsAccount) {
|
||||
ArrayList<SmsCampaign> smsCampaigns = retrieveSmsCampaigns("savings activated");
|
||||
if (smsCampaigns.size() > 0) {
|
||||
for (SmsCampaign campaign : smsCampaigns) {
|
||||
if (campaign.isActive()) {
|
||||
this.smsCampaignWritePlatformCommandHandler.insertDirectCampaignIntoSmsOutboundTable(savingsAccount,
|
||||
campaign);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void notifySavingsAccountRejected(final SavingsAccount savingsAccount) {
|
||||
ArrayList<SmsCampaign> smsCampaigns = retrieveSmsCampaigns("savings rejected");
|
||||
if (smsCampaigns.size() > 0) {
|
||||
for (SmsCampaign campaign : smsCampaigns) {
|
||||
if (campaign.isActive()) {
|
||||
this.smsCampaignWritePlatformCommandHandler.insertDirectCampaignIntoSmsOutboundTable(savingsAccount,
|
||||
campaign);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void sendSmsForLoanRepayment(LoanTransaction loanTransaction) {
|
||||
ArrayList<SmsCampaign> smsCampaigns = retrieveSmsCampaigns("loan repayment");
|
||||
if (smsCampaigns.size() > 0) {
|
||||
for (SmsCampaign smsCampaign : smsCampaigns) {
|
||||
if (smsCampaign.isActive()) {
|
||||
try {
|
||||
Loan loan = loanTransaction.getLoan();
|
||||
final Set<Client> groupClients = new HashSet<>();
|
||||
if (loan.hasInvalidLoanType()) {
|
||||
throw new InvalidLoanTypeException("Loan Type cannot be Invalid for the Triggered Sms Campaign");
|
||||
}
|
||||
if (loan.isGroupLoan()) {
|
||||
Group group = this.groupRepository.findOne(loan.getGroupId());
|
||||
groupClients.addAll(group.getClientMembers());
|
||||
} else {
|
||||
groupClients.add(loan.client());
|
||||
}
|
||||
HashMap<String, String> campaignParams = new ObjectMapper()
|
||||
.readValue(smsCampaign.getParamValue(), new TypeReference<HashMap<String, String>>() {
|
||||
});
|
||||
|
||||
if (groupClients.size() > 0) {
|
||||
for (Client client : groupClients) {
|
||||
HashMap<String, Object> smsParams = processRepaymentDataForSms(loanTransaction, client);
|
||||
for (String key : campaignParams.keySet()) {
|
||||
String value = campaignParams.get(key);
|
||||
String spvalue = null;
|
||||
boolean spkeycheck = smsParams.containsKey(key);
|
||||
if (spkeycheck) {
|
||||
spvalue = smsParams.get(key).toString();
|
||||
}
|
||||
if (spkeycheck && !(value.equals("-1") || spvalue.equals(value))) {
|
||||
if (key.equals("officeId")) {
|
||||
Office campaignOffice = this.officeRepository.findOne(Long.valueOf(value));
|
||||
if (campaignOffice
|
||||
.doesNotHaveAnOfficeInHierarchyWithId(client.getOffice().getId())) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
String message = this.smsCampaignWritePlatformCommandHandler.compileSmsTemplate(
|
||||
smsCampaign.getMessage(), smsCampaign.getCampaignName(), smsParams);
|
||||
Object mobileNo = smsParams.get("mobileNo");
|
||||
if (mobileNo != null) {
|
||||
SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, message,
|
||||
mobileNo.toString(), smsCampaign);
|
||||
this.smsMessageRepository.save(smsMessage);
|
||||
Collection<SmsMessage> messages = new ArrayList<>();
|
||||
messages.add(smsMessage);
|
||||
Map<SmsCampaign, Collection<SmsMessage>> smsDataMap = new HashMap<>();
|
||||
smsDataMap.put(smsCampaign, messages);
|
||||
this.smsMessageScheduledJobService.sendTriggeredMessages(smsDataMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
logger.error("smsParams does not contain the key: " + e.getMessage());
|
||||
} catch (final RuntimeException e) {
|
||||
logger.debug("Client Office Id and SMS Campaign Office id doesn't match");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendSmsForSavingsTransaction(final SavingsAccountTransaction savingsTransaction, boolean isDeposit) {
|
||||
String campaignName = isDeposit ? "savings deposit" : "savings withdrawal";
|
||||
ArrayList<SmsCampaign> smsCampaigns = retrieveSmsCampaigns(campaignName);
|
||||
if (smsCampaigns.size() > 0) {
|
||||
for (SmsCampaign smsCampaign : smsCampaigns) {
|
||||
if (smsCampaign.isActive()) {
|
||||
try {
|
||||
final SavingsAccount savingsAccount = savingsTransaction.getSavingsAccount();
|
||||
final Client client = savingsAccount.getClient();
|
||||
HashMap<String, String> campaignParams = new ObjectMapper()
|
||||
.readValue(smsCampaign.getParamValue(), new TypeReference<HashMap<String, String>>() {
|
||||
});
|
||||
HashMap<String, Object> smsParams = processSavingsTransactionDataForSms(savingsTransaction,
|
||||
client);
|
||||
for (String key : campaignParams.keySet()) {
|
||||
String value = campaignParams.get(key);
|
||||
String spvalue = null;
|
||||
boolean spkeycheck = smsParams.containsKey(key);
|
||||
if (spkeycheck) {
|
||||
spvalue = smsParams.get(key).toString();
|
||||
}
|
||||
if (spkeycheck && !(value.equals("-1") || spvalue.equals(value))) {
|
||||
if (key.equals("officeId")) {
|
||||
Office campaignOffice = this.officeRepository.findOne(Long.valueOf(value));
|
||||
if (campaignOffice
|
||||
.doesNotHaveAnOfficeInHierarchyWithId(client.getOffice().getId())) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
String message = this.smsCampaignWritePlatformCommandHandler
|
||||
.compileSmsTemplate(smsCampaign.getMessage(), smsCampaign.getCampaignName(), smsParams);
|
||||
Object mobileNo = smsParams.get("mobileNo");
|
||||
if (mobileNo != null) {
|
||||
SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, message,
|
||||
mobileNo.toString(), smsCampaign);
|
||||
this.smsMessageRepository.save(smsMessage);
|
||||
Collection<SmsMessage> messages = new ArrayList<>();
|
||||
messages.add(smsMessage);
|
||||
Map<SmsCampaign, Collection<SmsMessage>> smsDataMap = new HashMap<>();
|
||||
smsDataMap.put(smsCampaign, messages);
|
||||
this.smsMessageScheduledJobService.sendTriggeredMessages(smsDataMap);
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
logger.error("smsParams does not contain the key: " + e.getMessage());
|
||||
} catch (final RuntimeException e) {
|
||||
logger.debug("Client Office Id and SMS Campaign Office id doesn't match");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList<SmsCampaign> retrieveSmsCampaigns(String paramValue){
|
||||
Collection<SmsCampaign> initialSmsCampaignList = smsCampaignRepository.findByTriggerType(SmsCampaignTriggerType.TRIGGERED.getValue());
|
||||
ArrayList<SmsCampaign> smsCampaigns = new ArrayList<>();
|
||||
|
||||
for(SmsCampaign campaign : initialSmsCampaignList){
|
||||
if(campaign.getParamValue().toLowerCase().contains(paramValue)){
|
||||
smsCampaigns.add(campaign);
|
||||
}
|
||||
}
|
||||
return smsCampaigns;
|
||||
}
|
||||
|
||||
private HashMap<String, Object> processRepaymentDataForSms(final LoanTransaction loanTransaction, Client groupClient){
|
||||
|
||||
HashMap<String, Object> smsParams = new HashMap<String, Object>();
|
||||
Loan loan = loanTransaction.getLoan();
|
||||
final Client client;
|
||||
if(loan.isGroupLoan() && groupClient != null){
|
||||
client = groupClient;
|
||||
}else if(loan.isIndividualLoan()){
|
||||
client = loan.getClient();
|
||||
}else{
|
||||
throw new InvalidParameterException("");
|
||||
}
|
||||
|
||||
DateTimeFormatter timeFormatter = DateTimeFormat.forPattern("HH:mm");
|
||||
DateTimeFormatter dateFormatter = DateTimeFormat.forPattern("MMM:d:yyyy");
|
||||
|
||||
smsParams.put("id",loanTransaction.getLoan().getClientId());
|
||||
smsParams.put("firstname",client.getFirstname());
|
||||
smsParams.put("middlename",client.getMiddlename());
|
||||
smsParams.put("lastname",client.getLastname());
|
||||
smsParams.put("FullName",client.getDisplayName());
|
||||
smsParams.put("mobileNo",client.mobileNo());
|
||||
smsParams.put("LoanAmount",loan.getPrincpal());
|
||||
smsParams.put("LoanOutstanding",loanTransaction.getOutstandingLoanBalance());
|
||||
smsParams.put("loanId",loan.getId());
|
||||
smsParams.put("LoanAccountId", loan.getAccountNumber());
|
||||
smsParams.put("officeId", client.getOffice().getId());
|
||||
|
||||
if(client.getStaff() != null) {
|
||||
smsParams.put("loanOfficerId", client.getStaff().getId());
|
||||
}else {
|
||||
smsParams.put("loanOfficerId", -1);
|
||||
}
|
||||
|
||||
smsParams.put("repaymentAmount", loanTransaction.getAmount(loan.getCurrency()));
|
||||
smsParams.put("RepaymentDate", loanTransaction.getCreatedDateTime().toLocalDate().toString(dateFormatter));
|
||||
smsParams.put("RepaymentTime", loanTransaction.getCreatedDateTime().toLocalTime().toString(timeFormatter));
|
||||
|
||||
if(loanTransaction.getPaymentDetail() != null) {
|
||||
smsParams.put("receiptNumber", loanTransaction.getPaymentDetail().getReceiptNumber());
|
||||
}else {
|
||||
smsParams.put("receiptNumber", -1);
|
||||
}
|
||||
return smsParams;
|
||||
}
|
||||
|
||||
private HashMap<String, Object> processSavingsTransactionDataForSms(final SavingsAccountTransaction savingsAccountTransaction, Client client){
|
||||
|
||||
// {{savingsId}} {{id}} {{firstname}} {{middlename}} {{lastname}} {{FullName}} {{mobileNo}} {{savingsAccountId}} {{depositAmount}} {{balance}}
|
||||
|
||||
//transactionDate
|
||||
HashMap<String, Object> smsParams = new HashMap<String, Object>();
|
||||
SavingsAccount savingsAccount = savingsAccountTransaction.getSavingsAccount() ;
|
||||
DateTimeFormatter dateFormatter = DateTimeFormat.forPattern("MMM:d:yyyy");
|
||||
smsParams.put("clientId",client.getId());
|
||||
smsParams.put("firstname",client.getFirstname());
|
||||
smsParams.put("middlename",client.getMiddlename());
|
||||
smsParams.put("lastname",client.getLastname());
|
||||
smsParams.put("FullName",client.getDisplayName());
|
||||
smsParams.put("mobileNo",client.mobileNo());
|
||||
smsParams.put("savingsId", savingsAccount.getId()) ;
|
||||
smsParams.put("savingsAccountNo",savingsAccount.getAccountNumber());
|
||||
smsParams.put("withdrawAmount",savingsAccountTransaction.getAmount(savingsAccount.getCurrency()));
|
||||
smsParams.put("depositAmount",savingsAccountTransaction.getAmount(savingsAccount.getCurrency()));
|
||||
smsParams.put("balance",savingsAccount.getWithdrawableBalance());
|
||||
smsParams.put("officeId", client.getOffice().getId());
|
||||
smsParams.put("transactionDate", savingsAccountTransaction.getTransactionLocalDate().toString(dateFormatter)) ;
|
||||
smsParams.put("savingsTransactionId", savingsAccountTransaction.getId()) ;
|
||||
|
||||
if(client.getStaff() != null) {
|
||||
smsParams.put("loanOfficerId", client.getStaff().getId());
|
||||
}else {
|
||||
smsParams.put("loanOfficerId", -1);
|
||||
}
|
||||
|
||||
if(savingsAccountTransaction.getPaymentDetail() != null) {
|
||||
smsParams.put("receiptNumber", savingsAccountTransaction.getPaymentDetail().getReceiptNumber());
|
||||
}else {
|
||||
smsParams.put("receiptNumber", -1);
|
||||
}
|
||||
return smsParams;
|
||||
}
|
||||
|
||||
private class SendSmsOnLoanApproved implements BusinessEventListner{
|
||||
|
||||
@Override
|
||||
public void businessEventToBeExecuted(Map<BusinessEventNotificationConstants.BUSINESS_ENTITY, Object> businessEventEntity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void businessEventWasExecuted(Map<BusinessEventNotificationConstants.BUSINESS_ENTITY, Object> businessEventEntity) {
|
||||
Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.LOAN);
|
||||
if (entity instanceof Loan) {
|
||||
Loan loan = (Loan) entity;
|
||||
notifyAcceptedLoanOwner(loan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SendSmsOnLoanRejected implements BusinessEventListner{
|
||||
|
||||
@Override
|
||||
public void businessEventToBeExecuted(Map<BusinessEventNotificationConstants.BUSINESS_ENTITY, Object> businessEventEntity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void businessEventWasExecuted(Map<BusinessEventNotificationConstants.BUSINESS_ENTITY, Object> businessEventEntity) {
|
||||
Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.LOAN);
|
||||
if (entity instanceof Loan) {
|
||||
Loan loan = (Loan) entity;
|
||||
notifyRejectedLoanOwner(loan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SendSmsOnLoanRepayment implements BusinessEventListner{
|
||||
|
||||
@Override
|
||||
public void businessEventToBeExecuted(Map<BusinessEventNotificationConstants.BUSINESS_ENTITY, Object> businessEventEntity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void businessEventWasExecuted(Map<BusinessEventNotificationConstants.BUSINESS_ENTITY, Object> businessEventEntity) {
|
||||
Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.LOAN_TRANSACTION);
|
||||
if (entity instanceof LoanTransaction) {
|
||||
LoanTransaction loanTransaction = (LoanTransaction) entity;
|
||||
sendSmsForLoanRepayment(loanTransaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ClientActivatedListener implements BusinessEventListner {
|
||||
|
||||
@Override
|
||||
public void businessEventToBeExecuted(Map<BUSINESS_ENTITY, Object> businessEventEntity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> businessEventEntity) {
|
||||
Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.CLIENT);
|
||||
if(entity instanceof Client) {
|
||||
notifyClientActivated((Client)entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ClientRejectedListener implements BusinessEventListner {
|
||||
|
||||
@Override
|
||||
public void businessEventToBeExecuted(Map<BUSINESS_ENTITY, Object> businessEventEntity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> businessEventEntity) {
|
||||
Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.CLIENT);
|
||||
if(entity instanceof Client) {
|
||||
notifyClientRejected((Client)entity);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private class SavingsAccountActivatedListener implements BusinessEventListner {
|
||||
|
||||
@Override
|
||||
public void businessEventToBeExecuted(Map<BUSINESS_ENTITY, Object> businessEventEntity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> businessEventEntity) {
|
||||
Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.SAVING);
|
||||
if(entity instanceof SavingsAccount) {
|
||||
notifySavingsAccountActivated((SavingsAccount)entity);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private class SavingsAccountRejectedListener implements BusinessEventListner {
|
||||
|
||||
@Override
|
||||
public void businessEventToBeExecuted(Map<BUSINESS_ENTITY, Object> businessEventEntity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> businessEventEntity) {
|
||||
Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.SAVING);
|
||||
if(entity instanceof SavingsAccount) {
|
||||
notifySavingsAccountRejected((SavingsAccount)entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SavingsAccountTransactionListener implements BusinessEventListner {
|
||||
|
||||
final boolean isDeposit ;
|
||||
|
||||
public SavingsAccountTransactionListener(final boolean isDeposit) {
|
||||
this.isDeposit = isDeposit ;
|
||||
}
|
||||
@Override
|
||||
public void businessEventToBeExecuted(Map<BUSINESS_ENTITY, Object> businessEventEntity) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void businessEventWasExecuted(Map<BUSINESS_ENTITY, Object> businessEventEntity) {
|
||||
Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BUSINESS_ENTITY.SAVINGS_TRANSACTION);
|
||||
if(entity instanceof SavingsAccountTransaction) {
|
||||
sendSmsForSavingsTransaction((SavingsAccountTransaction)entity, this.isDeposit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
@@ -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.service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.data.SmsProviderData;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.data.TriggerTypeWithSubTypesData;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
|
||||
public interface SmsCampaignDropdownReadPlatformService {
|
||||
|
||||
Collection<EnumOptionData> retrieveCampaignTriggerTypes();
|
||||
|
||||
Collection<SmsProviderData> retrieveSmsProviders();
|
||||
|
||||
Collection<EnumOptionData> retrieveCampaignTypes();
|
||||
|
||||
Collection<EnumOptionData> retrieveWeeks();
|
||||
|
||||
Collection<EnumOptionData> retrieveMonths();
|
||||
|
||||
Collection<EnumOptionData> retrivePeriodFrequencyTypes();
|
||||
|
||||
Collection<TriggerTypeWithSubTypesData> getTriggerTypeAndSubTypes();
|
||||
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.fineract.infrastructure.campaigns.constants.CampaignType;
|
||||
import org.apache.fineract.infrastructure.campaigns.helper.SmsConfigUtils;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignConstants;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignEnumerations;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignTriggerType;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.data.CampaignTriggerWithSubTypes;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.data.SmsProviderData;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.data.TriggerTypeWithSubTypesData;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.exception.ConnectionFailureException;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarWeekDaysType;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarEnumerations;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@Service
|
||||
public class SmsCampaignDropdownReadPlatformServiceImpl implements SmsCampaignDropdownReadPlatformService {
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
private final SmsConfigUtils smsConfigUtils ;
|
||||
|
||||
@Autowired
|
||||
public SmsCampaignDropdownReadPlatformServiceImpl(final SmsConfigUtils smsConfigUtils) {
|
||||
this.restTemplate = new RestTemplate();
|
||||
this.smsConfigUtils = smsConfigUtils ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<EnumOptionData> retrieveCampaignTriggerTypes() {
|
||||
final List<EnumOptionData> triggerTypeCodeValues = Arrays.asList( //
|
||||
SmsCampaignEnumerations.smscampaignTriggerType(SmsCampaignTriggerType.DIRECT), //
|
||||
SmsCampaignEnumerations.smscampaignTriggerType(SmsCampaignTriggerType.SCHEDULE), //
|
||||
SmsCampaignEnumerations.smscampaignTriggerType(SmsCampaignTriggerType.TRIGGERED) //
|
||||
);
|
||||
|
||||
return triggerTypeCodeValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SmsProviderData> retrieveSmsProviders() {
|
||||
Collection<SmsProviderData> smsProviderOptions = new ArrayList<>();
|
||||
try {
|
||||
Map<String, Object> hostConfig = this.smsConfigUtils.getMessageGateWayRequestURI("smsbridges", null);
|
||||
URI uri = (URI) hostConfig.get("uri");
|
||||
HttpEntity<?> entity = (HttpEntity<?>) hostConfig.get("entity");
|
||||
ResponseEntity<Collection<SmsProviderData>> responseOne = restTemplate.exchange(uri, HttpMethod.GET, entity,
|
||||
new ParameterizedTypeReference<Collection<SmsProviderData>>() {});
|
||||
smsProviderOptions = responseOne.getBody();
|
||||
if (!responseOne.getStatusCode().equals(HttpStatus.OK)) {
|
||||
System.out.println(responseOne.getStatusCode().name());
|
||||
throw new ConnectionFailureException(SmsCampaignConstants.SMS_BRIDGE);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.getStackTrace();
|
||||
}
|
||||
return smsProviderOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<EnumOptionData> retrieveCampaignTypes() {
|
||||
final List<EnumOptionData> campaignTypeCodeValues = Arrays.asList( //
|
||||
SmsCampaignEnumerations.smscampaignType(CampaignType.SMS)//
|
||||
);
|
||||
return campaignTypeCodeValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<EnumOptionData> retrieveMonths() {
|
||||
Collection<EnumOptionData> monthsList = SmsCampaignEnumerations.calendarMonthType();
|
||||
return monthsList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<EnumOptionData> retrieveWeeks() {
|
||||
Collection<EnumOptionData> weeksList = CalendarEnumerations.calendarWeekDaysType(CalendarWeekDaysType.values());
|
||||
return weeksList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<EnumOptionData> retrivePeriodFrequencyTypes() {
|
||||
Collection<EnumOptionData> periodFrequencyTypes = SmsCampaignEnumerations
|
||||
.calendarPeriodFrequencyTypes(PeriodFrequencyType.values());
|
||||
return periodFrequencyTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<TriggerTypeWithSubTypesData> getTriggerTypeAndSubTypes() {
|
||||
return CampaignTriggerWithSubTypes.getTriggerTypeAndSubTypes();
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.data.SmsCampaignData;
|
||||
|
||||
public interface SmsCampaignReadPlatformService {
|
||||
|
||||
public SmsCampaignData retrieveOne(final Long campaignId);
|
||||
|
||||
public List<SmsCampaignData> retrieveAll();
|
||||
|
||||
public SmsCampaignData retrieveTemplate(final String reportType);
|
||||
|
||||
Collection<SmsCampaignData> retrieveAllScheduleActiveCampaign();
|
||||
|
||||
}
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.fineract.infrastructure.campaigns.constants.CampaignType;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignTriggerType;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.data.SmsBusinessRulesData;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.data.SmsCampaignData;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.data.SmsCampaignTimeLine;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.data.SmsProviderData;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.domain.SmsCampaignStatusEnumerations;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.exception.SmsCampaignNotFound;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
|
||||
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarDropdownReadPlatformService;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class SmsCampaignReadPlatformServiceImpl implements SmsCampaignReadPlatformService {
|
||||
|
||||
private final BusinessRuleMapper businessRuleMapper;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final SmsCampaignDropdownReadPlatformService smsCampaignDropdownReadPlatformService;
|
||||
private final SmsCampaignMapper smsCampaignMapper;
|
||||
private final CalendarDropdownReadPlatformService calendarDropdownReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public SmsCampaignReadPlatformServiceImpl(final RoutingDataSource dataSource,
|
||||
SmsCampaignDropdownReadPlatformService smsCampaignDropdownReadPlatformService,
|
||||
final CalendarDropdownReadPlatformService calendarDropdownReadPlatformService) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
businessRuleMapper = new BusinessRuleMapper();
|
||||
this.smsCampaignDropdownReadPlatformService = smsCampaignDropdownReadPlatformService;
|
||||
smsCampaignMapper = new SmsCampaignMapper();
|
||||
this.calendarDropdownReadPlatformService = calendarDropdownReadPlatformService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsCampaignData retrieveOne(Long campaignId) {
|
||||
final Integer isVisible = 1;
|
||||
try {
|
||||
final String sql = "select " + this.smsCampaignMapper.schema + " where sc.id = ? and sc.is_visible = ?";
|
||||
return this.jdbcTemplate.queryForObject(sql, this.smsCampaignMapper, new Object[] { campaignId, isVisible });
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new SmsCampaignNotFound(campaignId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SmsCampaignData> retrieveAll() {
|
||||
final Integer visible = 1;
|
||||
final String sql = "select " + this.smsCampaignMapper.schema() + " where sc.is_visible = ?";
|
||||
return this.jdbcTemplate.query(sql, this.smsCampaignMapper, new Object[] {visible});
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsCampaignData retrieveTemplate(final String reportType) {
|
||||
String sql = "select " + this.businessRuleMapper.schema();
|
||||
if (!StringUtils.isEmpty(reportType)) {
|
||||
sql = sql + " where sr.report_type = ?";
|
||||
}
|
||||
final Collection<SmsBusinessRulesData> businessRulesOptions = this.jdbcTemplate.query(sql, this.businessRuleMapper,
|
||||
new Object[] { reportType });
|
||||
final Collection<SmsProviderData> smsProviderOptions = this.smsCampaignDropdownReadPlatformService.retrieveSmsProviders();
|
||||
final Collection<EnumOptionData> campaignTypeOptions = this.smsCampaignDropdownReadPlatformService.retrieveCampaignTypes();
|
||||
final Collection<EnumOptionData> campaignTriggerTypeOptions = this.smsCampaignDropdownReadPlatformService
|
||||
.retrieveCampaignTriggerTypes();
|
||||
final Collection<EnumOptionData> months = this.smsCampaignDropdownReadPlatformService.retrieveMonths();
|
||||
final Collection<EnumOptionData> weekDays = this.smsCampaignDropdownReadPlatformService.retrieveWeeks();
|
||||
final Collection<EnumOptionData> frequencyTypeOptions = this.calendarDropdownReadPlatformService
|
||||
.retrieveCalendarFrequencyTypeOptions();
|
||||
final Collection<EnumOptionData> periodFrequencyOptions = this.smsCampaignDropdownReadPlatformService.retrivePeriodFrequencyTypes();
|
||||
//final Collection<TriggerTypeWithSubTypesData> triggerTypeSubTypeOptions = this.smsCampaignDropdownReadPlatformService.getTriggerTypeAndSubTypes();
|
||||
return SmsCampaignData.template(smsProviderOptions, campaignTypeOptions, businessRulesOptions, campaignTriggerTypeOptions, months,
|
||||
weekDays, frequencyTypeOptions, periodFrequencyOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SmsCampaignData> retrieveAllScheduleActiveCampaign() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final class BusinessRuleMapper implements ResultSetExtractor<List<SmsBusinessRulesData>> {
|
||||
|
||||
final String schema;
|
||||
|
||||
private BusinessRuleMapper() {
|
||||
final StringBuilder sql = new StringBuilder(300);
|
||||
sql.append("sr.id as id, ");
|
||||
sql.append("sr.report_name as reportName, ");
|
||||
sql.append("sr.report_type as reportType, ");
|
||||
sql.append("sr.report_subtype as reportSubType, ");
|
||||
sql.append("sr.description as description, ");
|
||||
sql.append("sp.parameter_variable as params, ");
|
||||
sql.append("sp.parameter_FormatType as paramType, ");
|
||||
sql.append("sp.parameter_label as paramLabel, ");
|
||||
sql.append("sp.parameter_name as paramName ");
|
||||
sql.append("from stretchy_report sr ");
|
||||
sql.append("left join stretchy_report_parameter as srp on srp.report_id = sr.id ");
|
||||
sql.append("left join stretchy_parameter as sp on sp.id = srp.parameter_id ");
|
||||
|
||||
this.schema = sql.toString();
|
||||
}
|
||||
|
||||
public String schema() {
|
||||
return this.schema;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SmsBusinessRulesData> extractData(ResultSet rs) throws SQLException, DataAccessException {
|
||||
List<SmsBusinessRulesData> smsBusinessRulesDataList = new ArrayList<SmsBusinessRulesData>();
|
||||
|
||||
SmsBusinessRulesData smsBusinessRulesData = null;
|
||||
|
||||
Map<Long, SmsBusinessRulesData> mapOfSameObjects = new HashMap<Long, SmsBusinessRulesData>();
|
||||
|
||||
while (rs.next()) {
|
||||
final Long id = rs.getLong("id");
|
||||
smsBusinessRulesData = mapOfSameObjects.get(id);
|
||||
if (smsBusinessRulesData == null) {
|
||||
final String reportName = rs.getString("reportName");
|
||||
final String reportType = rs.getString("reportType");
|
||||
final String reportSubType = rs.getString("reportSubType");
|
||||
final String paramName = rs.getString("paramName");
|
||||
final String paramLabel = rs.getString("paramLabel");
|
||||
final String description = rs.getString("description");
|
||||
|
||||
Map<String, Object> hashMap = new HashMap<String, Object>();
|
||||
hashMap.put(paramLabel, paramName);
|
||||
smsBusinessRulesData = SmsBusinessRulesData.instance(id, reportName, reportType, reportSubType, hashMap, description);
|
||||
mapOfSameObjects.put(id, smsBusinessRulesData);
|
||||
// add to the list
|
||||
smsBusinessRulesDataList.add(smsBusinessRulesData);
|
||||
}
|
||||
// add new paramType to the existing object
|
||||
Map<String, Object> hashMap = new HashMap<String, Object>();
|
||||
final String paramName = rs.getString("paramName");
|
||||
final String paramLabel = rs.getString("paramLabel");
|
||||
hashMap.put(paramLabel, paramName);
|
||||
|
||||
// get existing map and add new items to it
|
||||
smsBusinessRulesData.getReportParamName().putAll(hashMap);
|
||||
}
|
||||
|
||||
return smsBusinessRulesDataList;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class SmsCampaignMapper implements RowMapper<SmsCampaignData> {
|
||||
|
||||
final String schema;
|
||||
|
||||
private SmsCampaignMapper() {
|
||||
final StringBuilder sql = new StringBuilder(400);
|
||||
sql.append("sc.id as id, ");
|
||||
sql.append("sc.campaign_name as campaignName, ");
|
||||
sql.append("sc.campaign_type as campaignType, ");
|
||||
sql.append("sc.campaign_trigger_type as triggerType, ");
|
||||
sql.append("sc.report_id as runReportId, ");
|
||||
sql.append("sc.message as message, ");
|
||||
sql.append("sc.param_value as paramValue, ");
|
||||
sql.append("sc.status_enum as status, ");
|
||||
sql.append("sc.recurrence as recurrence, ");
|
||||
sql.append("sc.recurrence_start_date as recurrenceStartDate, ");
|
||||
sql.append("sc.next_trigger_date as nextTriggerDate, ");
|
||||
sql.append("sc.last_trigger_date as lastTriggerDate, ");
|
||||
sql.append("sc.submittedon_date as submittedOnDate, ");
|
||||
sql.append("sbu.username as submittedByUsername, ");
|
||||
sql.append("sc.closedon_date as closedOnDate, ");
|
||||
sql.append("clu.username as closedByUsername, ");
|
||||
sql.append("acu.username as activatedByUsername, ");
|
||||
sql.append("sc.approvedon_date as activatedOnDate, ");
|
||||
sql.append("sr.report_name as reportName, ");
|
||||
sql.append("provider_id as providerId ");
|
||||
sql.append("from sms_campaign sc ");
|
||||
sql.append("left join m_appuser sbu on sbu.id = sc.submittedon_userid ");
|
||||
sql.append("left join m_appuser acu on acu.id = sc.approvedon_userid ");
|
||||
sql.append("left join m_appuser clu on clu.id = sc.closedon_userid ");
|
||||
sql.append("left join stretchy_report sr on sr.id = sc.report_id ");
|
||||
|
||||
this.schema = sql.toString();
|
||||
}
|
||||
|
||||
public String schema() {
|
||||
return this.schema;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsCampaignData mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
final Long id = JdbcSupport.getLong(rs, "id");
|
||||
final String campaignName = rs.getString("campaignName");
|
||||
final Integer campaignType = JdbcSupport.getInteger(rs, "campaignType");
|
||||
final EnumOptionData campaignTypeEnum = CampaignType.campaignType(campaignType);
|
||||
final Long runReportId = JdbcSupport.getLong(rs, "runReportId");
|
||||
final String paramValue = rs.getString("paramValue");
|
||||
final String message = rs.getString("message");
|
||||
|
||||
final Integer statusId = JdbcSupport.getInteger(rs, "status");
|
||||
final EnumOptionData status = SmsCampaignStatusEnumerations.status(statusId);
|
||||
final Integer triggerType = JdbcSupport.getInteger(rs, "triggerType");
|
||||
final EnumOptionData triggerTypeEnum = SmsCampaignTriggerType.triggerType(triggerType);
|
||||
|
||||
final DateTime nextTriggerDate = JdbcSupport.getDateTime(rs, "nextTriggerDate");
|
||||
final LocalDate lastTriggerDate = JdbcSupport.getLocalDate(rs, "lastTriggerDate");
|
||||
|
||||
final LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate");
|
||||
final String closedByUsername = rs.getString("closedByUsername");
|
||||
|
||||
final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
|
||||
final String submittedByUsername = rs.getString("submittedByUsername");
|
||||
|
||||
final LocalDate activatedOnDate = JdbcSupport.getLocalDate(rs, "activatedOnDate");
|
||||
final String activatedByUsername = rs.getString("activatedByUsername");
|
||||
final String recurrence = rs.getString("recurrence");
|
||||
final DateTime recurrenceStartDate = JdbcSupport.getDateTime(rs, "recurrenceStartDate");
|
||||
final SmsCampaignTimeLine smsCampaignTimeLine = new SmsCampaignTimeLine(submittedOnDate, submittedByUsername, activatedOnDate,
|
||||
activatedByUsername, closedOnDate, closedByUsername);
|
||||
final String reportName = rs.getString("reportName");
|
||||
final Long providerId = rs.getLong("providerId");
|
||||
|
||||
return SmsCampaignData.instance(id, campaignName, campaignTypeEnum, triggerTypeEnum, runReportId, reportName, paramValue, status, message, nextTriggerDate, lastTriggerDate,
|
||||
smsCampaignTimeLine, recurrenceStartDate, recurrence, providerId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.data.CampaignPreviewData;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.domain.SmsCampaign;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonQuery;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
|
||||
|
||||
public interface SmsCampaignWritePlatformService {
|
||||
|
||||
CommandProcessingResult create(JsonCommand command);
|
||||
|
||||
CommandProcessingResult update(Long resourceId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult delete(Long resourceId);
|
||||
|
||||
CommandProcessingResult activateSmsCampaign(Long campaignId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult closeSmsCampaign(Long campaignId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult reactivateSmsCampaign(Long campaignId, JsonCommand command);
|
||||
|
||||
void insertDirectCampaignIntoSmsOutboundTable(Loan loan, SmsCampaign smsCampaign);
|
||||
|
||||
String compileSmsTemplate(String textMessageTemplate, String campaignName, Map<String, Object> smsParams);
|
||||
|
||||
CampaignPreviewData previewMessage(JsonQuery query);
|
||||
|
||||
public void storeTemplateMessageIntoSmsOutBoundTable() throws JobExecutionException;
|
||||
|
||||
public void insertDirectCampaignIntoSmsOutboundTable(final Client client, final SmsCampaign smsCampaign) ;
|
||||
|
||||
public void insertDirectCampaignIntoSmsOutboundTable(final SavingsAccount savingsAccount, final SmsCampaign smsCampaign) ;
|
||||
|
||||
}
|
||||
+687
@@ -0,0 +1,687 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
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.data.CampaignPreviewData;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.domain.SmsCampaign;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.domain.SmsCampaignRepository;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.exception.SmsCampaignMustBeClosedToBeDeletedException;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.exception.SmsCampaignMustBeClosedToEditException;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.exception.SmsCampaignNotFound;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.serialization.SmsCampaignValidator;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonQuery;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.infrastructure.dataqueries.data.GenericResultsetData;
|
||||
import org.apache.fineract.infrastructure.dataqueries.domain.Report;
|
||||
import org.apache.fineract.infrastructure.dataqueries.domain.ReportRepository;
|
||||
import org.apache.fineract.infrastructure.dataqueries.exception.ReportNotFoundException;
|
||||
import org.apache.fineract.infrastructure.dataqueries.service.GenericDataService;
|
||||
import org.apache.fineract.infrastructure.dataqueries.service.ReadReportingService;
|
||||
import org.apache.fineract.infrastructure.jobs.annotation.CronTarget;
|
||||
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
|
||||
import org.apache.fineract.infrastructure.jobs.service.JobName;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.infrastructure.sms.domain.SmsMessage;
|
||||
import org.apache.fineract.infrastructure.sms.domain.SmsMessageRepository;
|
||||
import org.apache.fineract.infrastructure.sms.domain.SmsMessageStatusType;
|
||||
import org.apache.fineract.infrastructure.sms.scheduler.SmsMessageScheduledJobService;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.group.domain.Group;
|
||||
import org.apache.fineract.portfolio.group.domain.GroupRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.InvalidLoanTypeException;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.codehaus.jackson.JsonParseException;
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.codehaus.jackson.type.TypeReference;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.LocalDateTime;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.github.mustachejava.DefaultMustacheFactory;
|
||||
import com.github.mustachejava.Mustache;
|
||||
import com.github.mustachejava.MustacheFactory;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
@Service
|
||||
public class SmsCampaignWritePlatformServiceJpaImpl implements SmsCampaignWritePlatformService {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(SmsCampaignWritePlatformServiceJpaImpl.class);
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
|
||||
private final SmsCampaignRepository smsCampaignRepository;
|
||||
private final SmsCampaignValidator smsCampaignValidator;
|
||||
private final ReportRepository reportRepository;
|
||||
private final SmsMessageRepository smsMessageRepository;
|
||||
private final ClientRepositoryWrapper clientRepositoryWrapper;
|
||||
private final GroupRepository groupRepository;
|
||||
private final ReadReportingService readReportingService;
|
||||
private final GenericDataService genericDataService;
|
||||
private final FromJsonHelper fromJsonHelper;
|
||||
|
||||
private final SmsMessageScheduledJobService smsMessageScheduledJobService;
|
||||
|
||||
@Autowired
|
||||
public SmsCampaignWritePlatformServiceJpaImpl(final PlatformSecurityContext context, final SmsCampaignRepository smsCampaignRepository,
|
||||
final SmsCampaignValidator smsCampaignValidator, final ReportRepository reportRepository,
|
||||
final SmsMessageRepository smsMessageRepository, final ClientRepositoryWrapper clientRepositoryWrapper,
|
||||
final ReadReportingService readReportingService, final GenericDataService genericDataService,
|
||||
final FromJsonHelper fromJsonHelper, final GroupRepository groupRepository,
|
||||
final SmsMessageScheduledJobService smsMessageScheduledJobService) {
|
||||
this.context = context;
|
||||
this.smsCampaignRepository = smsCampaignRepository;
|
||||
this.smsCampaignValidator = smsCampaignValidator;
|
||||
this.reportRepository = reportRepository;
|
||||
this.smsMessageRepository = smsMessageRepository;
|
||||
this.clientRepositoryWrapper = clientRepositoryWrapper;
|
||||
this.readReportingService = readReportingService;
|
||||
this.genericDataService = genericDataService;
|
||||
this.fromJsonHelper = fromJsonHelper;
|
||||
this.groupRepository = groupRepository;
|
||||
this.smsMessageScheduledJobService = smsMessageScheduledJobService ;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult create(JsonCommand command) {
|
||||
|
||||
final AppUser currentUser = this.context.authenticatedUser();
|
||||
this.smsCampaignValidator.validateCreate(command.json());
|
||||
final Long runReportId = command.longValueOfParameterNamed(SmsCampaignValidator.runReportId);
|
||||
Report report = this.reportRepository.findOne(runReportId);
|
||||
if (report == null) { throw new ReportNotFoundException(runReportId); }
|
||||
SmsCampaign smsCampaign = SmsCampaign.instance(currentUser, report, command);
|
||||
|
||||
this.smsCampaignRepository.save(smsCampaign);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(smsCampaign.getId()) //
|
||||
.build();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult update(final Long resourceId, final JsonCommand command) {
|
||||
try {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
this.smsCampaignValidator.validateForUpdate(command.json());
|
||||
final SmsCampaign smsCampaign = this.smsCampaignRepository.findOne(resourceId);
|
||||
|
||||
if (smsCampaign == null) { throw new SmsCampaignNotFound(resourceId); }
|
||||
if (smsCampaign.isActive()) { throw new SmsCampaignMustBeClosedToEditException(smsCampaign.getId()); }
|
||||
final Map<String, Object> changes = smsCampaign.update(command);
|
||||
|
||||
if (changes.containsKey(SmsCampaignValidator.runReportId)) {
|
||||
final Long newValue = command.longValueOfParameterNamed(SmsCampaignValidator.runReportId);
|
||||
final Report reportId = this.reportRepository.findOne(newValue);
|
||||
if (reportId == null) { throw new ReportNotFoundException(newValue); }
|
||||
;
|
||||
smsCampaign.updateBusinessRuleId(reportId);
|
||||
}
|
||||
|
||||
if (!changes.isEmpty()) {
|
||||
this.smsCampaignRepository.saveAndFlush(smsCampaign);
|
||||
}
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(resourceId) //
|
||||
.with(changes) //
|
||||
.build();
|
||||
} catch (final DataIntegrityViolationException dve) {
|
||||
handleDataIntegrityIssues(command, dve);
|
||||
return CommandProcessingResult.empty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult delete(final Long resourceId) {
|
||||
this.context.authenticatedUser();
|
||||
final SmsCampaign smsCampaign = this.smsCampaignRepository.findOne(resourceId);
|
||||
|
||||
if (smsCampaign == null) { throw new SmsCampaignNotFound(resourceId); }
|
||||
if (smsCampaign.isActive()) { throw new SmsCampaignMustBeClosedToBeDeletedException(smsCampaign.getId()); }
|
||||
|
||||
/*
|
||||
* Do not delete but set a boolean is_visible to zero
|
||||
*/
|
||||
smsCampaign.delete();
|
||||
this.smsCampaignRepository.saveAndFlush(smsCampaign);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(smsCampaign.getId()) //
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
private void insertDirectCampaignIntoSmsOutboundTable(SmsCampaign smsCampaign) {
|
||||
try {
|
||||
HashMap<String, String> campaignParams = new ObjectMapper().readValue(smsCampaign.getParamValue(),
|
||||
new TypeReference<HashMap<String, String>>() {});
|
||||
|
||||
HashMap<String, String> queryParamForRunReport = new ObjectMapper().readValue(smsCampaign.getParamValue(),
|
||||
new TypeReference<HashMap<String, String>>() {});
|
||||
|
||||
List<HashMap<String, Object>> runReportObject = this.getRunReportByServiceImpl(campaignParams.get("reportName"),
|
||||
queryParamForRunReport);
|
||||
|
||||
if (runReportObject != null) {
|
||||
for (HashMap<String, Object> entry : runReportObject) {
|
||||
String textMessage = this.compileSmsTemplate(smsCampaign.getMessage(), smsCampaign.getCampaignName(), entry);
|
||||
Integer clientId = (Integer) entry.get("id");
|
||||
Object mobileNo = entry.get("mobileNo");
|
||||
|
||||
Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId.longValue());
|
||||
if (mobileNo != null) {
|
||||
// String countryCode = this.smsReadPlatformService.retrieveCountryCode(client.getOffice().getId()).getCountryCode();
|
||||
SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, textMessage, mobileNo.toString(),
|
||||
smsCampaign);
|
||||
this.smsMessageRepository.save(smsMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
// TODO throw something here
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertDirectCampaignIntoSmsOutboundTable(final Loan loan, final SmsCampaign smsCampaign) {
|
||||
try {
|
||||
if (loan.hasInvalidLoanType()) { throw new InvalidLoanTypeException("Loan Type cannot be 0 for the Triggered Sms Campaign"); }
|
||||
|
||||
Set<Client> clientSet = new HashSet<>();
|
||||
|
||||
HashMap<String, String> campaignParams = new ObjectMapper().readValue(smsCampaign.getParamValue(),
|
||||
new TypeReference<HashMap<String, String>>() {});
|
||||
campaignParams.put("loanId", loan.getId().toString());
|
||||
|
||||
HashMap<String, String> queryParamForRunReport = new ObjectMapper().readValue(smsCampaign.getParamValue(),
|
||||
new TypeReference<HashMap<String, String>>() {});
|
||||
queryParamForRunReport.put("loanId", loan.getId().toString());
|
||||
|
||||
if (loan.isGroupLoan()) {
|
||||
Group group = this.groupRepository.findOne(loan.getGroupId());
|
||||
clientSet.addAll(group.getClientMembers());
|
||||
queryParamForRunReport.put("groupId", group.getId().toString());
|
||||
} else {
|
||||
Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(loan.getClientId());
|
||||
clientSet.add(client);
|
||||
}
|
||||
|
||||
for (Client client : clientSet) {
|
||||
campaignParams.put("clientId", client.getId().toString());
|
||||
queryParamForRunReport.put("clientId", client.getId().toString());
|
||||
|
||||
List<HashMap<String, Object>> runReportObject = this.getRunReportByServiceImpl(campaignParams.get("reportName"),
|
||||
queryParamForRunReport);
|
||||
|
||||
if (runReportObject != null && runReportObject.size() > 0) {
|
||||
for (HashMap<String, Object> entry : runReportObject) {
|
||||
String textMessage = this.compileSmsTemplate(smsCampaign.getMessage(), smsCampaign.getCampaignName(), entry);
|
||||
Object mobileNo = entry.get("mobileNo");
|
||||
|
||||
if (mobileNo != null) {
|
||||
SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, textMessage, mobileNo.toString(),
|
||||
smsCampaign);
|
||||
smsMessage.setStatusType(SmsMessageStatusType.WAITING_FOR_DELIVERY_REPORT.getValue());
|
||||
this.smsMessageRepository.save(smsMessage);
|
||||
Collection<SmsMessage> messages = new ArrayList<>() ;
|
||||
messages.add(smsMessage) ;
|
||||
Map<SmsCampaign, Collection<SmsMessage>> smsDataMap = new HashMap<>() ;
|
||||
smsDataMap.put(smsCampaign, messages) ;
|
||||
this.smsMessageScheduledJobService.sendTriggeredMessages(smsDataMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
System.out.println("IOException: " + e.getMessage());
|
||||
} catch (final RuntimeException e) {
|
||||
System.out.println("RuntimeException: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertDirectCampaignIntoSmsOutboundTable(final Client client, final SmsCampaign smsCampaign) {
|
||||
try {
|
||||
HashMap<String, String> campaignParams = new ObjectMapper().readValue(smsCampaign.getParamValue(),
|
||||
new TypeReference<HashMap<String, String>>() {});
|
||||
campaignParams.put("clientId", client.getId().toString());
|
||||
HashMap<String, String> queryParamForRunReport = new ObjectMapper().readValue(smsCampaign.getParamValue(),
|
||||
new TypeReference<HashMap<String, String>>() {});
|
||||
|
||||
campaignParams.put("clientId", client.getId().toString());
|
||||
queryParamForRunReport.put("clientId", client.getId().toString());
|
||||
|
||||
List<HashMap<String, Object>> runReportObject = this
|
||||
.getRunReportByServiceImpl(campaignParams.get("reportName"), queryParamForRunReport);
|
||||
|
||||
if (runReportObject != null && runReportObject.size() > 0) {
|
||||
for (HashMap<String, Object> entry : runReportObject) {
|
||||
String textMessage = this.compileSmsTemplate(smsCampaign.getMessage(),
|
||||
smsCampaign.getCampaignName(), entry);
|
||||
Object mobileNo = entry.get("mobileNo");
|
||||
|
||||
if (mobileNo != null) {
|
||||
SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, textMessage,
|
||||
mobileNo.toString(), smsCampaign);
|
||||
smsMessage.setStatusType(SmsMessageStatusType.WAITING_FOR_DELIVERY_REPORT.getValue());
|
||||
this.smsMessageRepository.save(smsMessage);
|
||||
Collection<SmsMessage> messages = new ArrayList<>();
|
||||
messages.add(smsMessage);
|
||||
Map<SmsCampaign, Collection<SmsMessage>> smsDataMap = new HashMap<>();
|
||||
smsDataMap.put(smsCampaign, messages);
|
||||
this.smsMessageScheduledJobService.sendTriggeredMessages(smsDataMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
System.out.println("IOException: " + e.getMessage());
|
||||
} catch (final RuntimeException e) {
|
||||
System.out.println("RuntimeException: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertDirectCampaignIntoSmsOutboundTable(final SavingsAccount savingsAccount, final SmsCampaign smsCampaign) {
|
||||
try {
|
||||
HashMap<String, String> campaignParams = new ObjectMapper().readValue(smsCampaign.getParamValue(),
|
||||
new TypeReference<HashMap<String, String>>() {});
|
||||
campaignParams.put("savingsId", savingsAccount.getId().toString());
|
||||
HashMap<String, String> queryParamForRunReport = new ObjectMapper().readValue(smsCampaign.getParamValue(),
|
||||
new TypeReference<HashMap<String, String>>() {});
|
||||
queryParamForRunReport.put("savingsId", savingsAccount.getId().toString());
|
||||
|
||||
Client client = savingsAccount.getClient() ;
|
||||
List<HashMap<String, Object>> runReportObject = this
|
||||
.getRunReportByServiceImpl(campaignParams.get("reportName"), queryParamForRunReport);
|
||||
|
||||
if (runReportObject != null && runReportObject.size() > 0) {
|
||||
for (HashMap<String, Object> entry : runReportObject) {
|
||||
String textMessage = this.compileSmsTemplate(smsCampaign.getMessage(),
|
||||
smsCampaign.getCampaignName(), entry);
|
||||
Object mobileNo = entry.get("mobileNo");
|
||||
|
||||
if (mobileNo != null) {
|
||||
SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, textMessage,
|
||||
mobileNo.toString(), smsCampaign);
|
||||
smsMessage.setStatusType(SmsMessageStatusType.WAITING_FOR_DELIVERY_REPORT.getValue());
|
||||
this.smsMessageRepository.save(smsMessage);
|
||||
Collection<SmsMessage> messages = new ArrayList<>();
|
||||
messages.add(smsMessage);
|
||||
Map<SmsCampaign, Collection<SmsMessage>> smsDataMap = new HashMap<>();
|
||||
smsDataMap.put(smsCampaign, messages);
|
||||
this.smsMessageScheduledJobService.sendTriggeredMessages(smsDataMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
System.out.println("IOException: " + e.getMessage());
|
||||
} catch (final RuntimeException e) {
|
||||
System.out.println("RuntimeException: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTriggerDates(Long campaignId) {
|
||||
final SmsCampaign smsCampaign = this.smsCampaignRepository.findOne(campaignId);
|
||||
if (smsCampaign == null) { throw new SmsCampaignNotFound(campaignId); }
|
||||
LocalDateTime nextTriggerDate = smsCampaign.getNextTriggerDate();
|
||||
smsCampaign.setLastTriggerDate(nextTriggerDate.toDate());
|
||||
// calculate new trigger date and insert into next trigger date
|
||||
|
||||
/**
|
||||
* next run time has to be in the future if not calculate a new future
|
||||
* date
|
||||
*/
|
||||
LocalDate nextRuntime = CalendarUtils.getNextRecurringDate(smsCampaign.getRecurrence(), smsCampaign.getNextTriggerDate()
|
||||
.toLocalDate(), nextTriggerDate.toLocalDate());
|
||||
if (nextRuntime.isBefore(DateUtils.getLocalDateOfTenant())) { // means
|
||||
// next
|
||||
// run
|
||||
// time is
|
||||
// in the
|
||||
// past
|
||||
// calculate
|
||||
// a new
|
||||
// future
|
||||
// date
|
||||
nextRuntime = CalendarUtils.getNextRecurringDate(smsCampaign.getRecurrence(), smsCampaign.getNextTriggerDate().toLocalDate(),
|
||||
DateUtils.getLocalDateOfTenant());
|
||||
}
|
||||
final LocalDateTime getTime = smsCampaign.getRecurrenceStartDateTime();
|
||||
final String dateString = nextRuntime.toString() + " " + getTime.getHourOfDay() + ":" + getTime.getMinuteOfHour() + ":"
|
||||
+ getTime.getSecondOfMinute();
|
||||
final DateTimeFormatter simpleDateFormat = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
|
||||
final LocalDateTime newTriggerDateWithTime = LocalDateTime.parse(dateString, simpleDateFormat);
|
||||
|
||||
smsCampaign.setNextTriggerDate(newTriggerDateWithTime.toDate());
|
||||
this.smsCampaignRepository.saveAndFlush(smsCampaign);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult activateSmsCampaign(Long campaignId, JsonCommand command) {
|
||||
final AppUser currentUser = this.context.authenticatedUser();
|
||||
|
||||
this.smsCampaignValidator.validateActivation(command.json());
|
||||
|
||||
final SmsCampaign smsCampaign = this.smsCampaignRepository.findOne(campaignId);
|
||||
|
||||
if (smsCampaign == null) { throw new SmsCampaignNotFound(campaignId); }
|
||||
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
final LocalDate activationDate = command.localDateValueOfParameterNamed("activationDate");
|
||||
|
||||
smsCampaign.activate(currentUser, fmt, activationDate);
|
||||
|
||||
this.smsCampaignRepository.saveAndFlush(smsCampaign);
|
||||
|
||||
if (smsCampaign.isDirect()) {
|
||||
insertDirectCampaignIntoSmsOutboundTable(smsCampaign);
|
||||
} else if (smsCampaign.isSchedule()) {
|
||||
|
||||
/**
|
||||
* if recurrence start date is in the future calculate next trigger
|
||||
* date if not use recurrence start date us next trigger date when
|
||||
* activating
|
||||
*/
|
||||
LocalDate nextTriggerDate = null;
|
||||
if (smsCampaign.getRecurrenceStartDateTime().isBefore(tenantDateTime())) {
|
||||
nextTriggerDate = CalendarUtils.getNextRecurringDate(smsCampaign.getRecurrence(), smsCampaign.getRecurrenceStartDate(),
|
||||
DateUtils.getLocalDateOfTenant());
|
||||
} else {
|
||||
nextTriggerDate = smsCampaign.getRecurrenceStartDate();
|
||||
}
|
||||
// to get time of tenant
|
||||
final LocalDateTime getTime = smsCampaign.getRecurrenceStartDateTime();
|
||||
|
||||
final String dateString = nextTriggerDate.toString() + " " + getTime.getHourOfDay() + ":" + getTime.getMinuteOfHour() + ":"
|
||||
+ getTime.getSecondOfMinute();
|
||||
final DateTimeFormatter simpleDateFormat = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
|
||||
final LocalDateTime nextTriggerDateWithTime = LocalDateTime.parse(dateString, simpleDateFormat);
|
||||
|
||||
smsCampaign.setNextTriggerDate(nextTriggerDateWithTime.toDate());
|
||||
this.smsCampaignRepository.saveAndFlush(smsCampaign);
|
||||
}
|
||||
|
||||
/*
|
||||
* if campaign is direct insert campaign message into sms outbound table
|
||||
* else if its a schedule create a job process for it
|
||||
*/
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(smsCampaign.getId()) //
|
||||
.build();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult closeSmsCampaign(Long campaignId, JsonCommand command) {
|
||||
|
||||
final AppUser currentUser = this.context.authenticatedUser();
|
||||
this.smsCampaignValidator.validateClosedDate(command.json());
|
||||
|
||||
final SmsCampaign smsCampaign = this.smsCampaignRepository.findOne(campaignId);
|
||||
if (smsCampaign == null) { throw new SmsCampaignNotFound(campaignId); }
|
||||
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
final LocalDate closureDate = command.localDateValueOfParameterNamed("closureDate");
|
||||
|
||||
smsCampaign.close(currentUser, fmt, closureDate);
|
||||
|
||||
this.smsCampaignRepository.saveAndFlush(smsCampaign);
|
||||
// this.serviceui.sendMessagesToGateway();
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(smsCampaign.getId()) //
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String compileSmsTemplate(final String textMessageTemplate, final String campaignName, final Map<String, Object> smsParams) {
|
||||
final MustacheFactory mf = new DefaultMustacheFactory();
|
||||
final Mustache mustache = mf.compile(new StringReader(textMessageTemplate), campaignName);
|
||||
|
||||
final StringWriter stringWriter = new StringWriter();
|
||||
mustache.execute(stringWriter, smsParams);
|
||||
|
||||
return stringWriter.toString();
|
||||
}
|
||||
|
||||
private List<HashMap<String, Object>> getRunReportByServiceImpl(final String reportName, final Map<String, String> queryParams)
|
||||
throws IOException {
|
||||
final String reportType = "report";
|
||||
|
||||
List<HashMap<String, Object>> resultList = new ArrayList<>();
|
||||
final GenericResultsetData results = this.readReportingService.retrieveGenericResultSetForSmsCampaign(reportName, reportType,
|
||||
queryParams);
|
||||
|
||||
try {
|
||||
final String response = this.genericDataService.generateJsonFromGenericResultsetData(results);
|
||||
resultList = new ObjectMapper().readValue(response, new TypeReference<List<HashMap<String, Object>>>() {});
|
||||
} catch (JsonParseException e) {
|
||||
logger.info("Conversion of report query results to JSON failed: " + e.getMessage() + " - Location: " + e.getLocation());
|
||||
return resultList;
|
||||
}
|
||||
// loop changes array date to string date
|
||||
for (HashMap<String, Object> entry : resultList) {
|
||||
for (Map.Entry<String, Object> map : entry.entrySet()) {
|
||||
String key = map.getKey();
|
||||
Object ob = map.getValue();
|
||||
if (ob instanceof ArrayList && ((ArrayList) ob).size() == 3) {
|
||||
String changeArrayDateToStringDate = ((ArrayList) ob).get(2).toString() + "-" + ((ArrayList) ob).get(1).toString()
|
||||
+ "-" + ((ArrayList) ob).get(0).toString();
|
||||
entry.put(key, changeArrayDateToStringDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CampaignPreviewData previewMessage(final JsonQuery query) {
|
||||
CampaignPreviewData campaignMessage = null;
|
||||
this.context.authenticatedUser();
|
||||
this.smsCampaignValidator.validatePreviewMessage(query.json());
|
||||
// final String smsParams =
|
||||
// this.fromJsonHelper.extractJsonObjectNamed("paramValue",
|
||||
// query.parsedJson()).getAsString();
|
||||
final JsonElement smsParamsElement = this.fromJsonHelper
|
||||
.extractJsonObjectNamed(SmsCampaignValidator.paramValue, query.parsedJson());
|
||||
String smsParams = smsParamsElement.toString();
|
||||
final String textMessageTemplate = this.fromJsonHelper.extractStringNamed("message", query.parsedJson());
|
||||
|
||||
try {
|
||||
HashMap<String, String> campaignParams = new ObjectMapper().readValue(smsParams,
|
||||
new TypeReference<HashMap<String, String>>() {});
|
||||
|
||||
HashMap<String, String> queryParamForRunReport = new ObjectMapper().readValue(smsParams,
|
||||
new TypeReference<HashMap<String, String>>() {});
|
||||
|
||||
List<HashMap<String, Object>> runReportObject = this.getRunReportByServiceImpl(campaignParams.get("reportName"),
|
||||
queryParamForRunReport);
|
||||
|
||||
if (runReportObject != null && !runReportObject.isEmpty()) {
|
||||
for (HashMap<String, Object> entry : runReportObject) {
|
||||
// add string object to campaignParam object
|
||||
String textMessage = this.compileSmsTemplate(textMessageTemplate, "SmsCampaign", entry);
|
||||
if (!textMessage.isEmpty()) {
|
||||
final Integer totalMessage = runReportObject.size();
|
||||
campaignMessage = new CampaignPreviewData(textMessage, totalMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
campaignMessage = new CampaignPreviewData(textMessageTemplate, 0);
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
// TODO throw something here
|
||||
}
|
||||
return campaignMessage;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult reactivateSmsCampaign(final Long campaignId, JsonCommand command) {
|
||||
|
||||
this.smsCampaignValidator.validateActivation(command.json());
|
||||
|
||||
final AppUser currentUser = this.context.authenticatedUser();
|
||||
|
||||
final SmsCampaign smsCampaign = this.smsCampaignRepository.findOne(campaignId);
|
||||
|
||||
if (smsCampaign == null) { throw new SmsCampaignNotFound(campaignId); }
|
||||
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
final LocalDate reactivationDate = command.localDateValueOfParameterNamed("activationDate");
|
||||
smsCampaign.reactivate(currentUser, fmt, reactivationDate);
|
||||
if (smsCampaign.isDirect()) {
|
||||
insertDirectCampaignIntoSmsOutboundTable(smsCampaign);
|
||||
} else if (smsCampaign.isSchedule()) {
|
||||
|
||||
/**
|
||||
* if recurrence start date is in the future calculate next trigger
|
||||
* date if not use recurrence start date us next trigger date when
|
||||
* activating
|
||||
*/
|
||||
LocalDate nextTriggerDate = null;
|
||||
if (smsCampaign.getRecurrenceStartDateTime().isBefore(tenantDateTime())) {
|
||||
nextTriggerDate = CalendarUtils.getNextRecurringDate(smsCampaign.getRecurrence(), smsCampaign.getRecurrenceStartDate(),
|
||||
DateUtils.getLocalDateOfTenant());
|
||||
} else {
|
||||
nextTriggerDate = smsCampaign.getRecurrenceStartDate();
|
||||
}
|
||||
// to get time of tenant
|
||||
final LocalDateTime getTime = smsCampaign.getRecurrenceStartDateTime();
|
||||
|
||||
final String dateString = nextTriggerDate.toString() + " " + getTime.getHourOfDay() + ":" + getTime.getMinuteOfHour() + ":"
|
||||
+ getTime.getSecondOfMinute();
|
||||
final DateTimeFormatter simpleDateFormat = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
|
||||
final LocalDateTime nextTriggerDateWithTime = LocalDateTime.parse(dateString, simpleDateFormat);
|
||||
|
||||
smsCampaign.setNextTriggerDate(nextTriggerDateWithTime.toDate());
|
||||
}
|
||||
this.smsCampaignRepository.saveAndFlush(smsCampaign);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(smsCampaign.getId()) //
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@CronTarget(jobName = JobName.UPDATE_SMS_OUTBOUND_WITH_CAMPAIGN_MESSAGE)
|
||||
public void storeTemplateMessageIntoSmsOutBoundTable() throws JobExecutionException {
|
||||
final Collection<SmsCampaign> smsCampaignDataCollection = this.smsCampaignRepository.findByCampaignTypeAndTriggerTypeAndStatus(
|
||||
CampaignType.SMS.getValue(), SmsCampaignTriggerType.SCHEDULE.getValue(), SmsCampaignStatus.ACTIVE.getValue());
|
||||
if (smsCampaignDataCollection != null) {
|
||||
for (SmsCampaign smsCampaign : smsCampaignDataCollection) {
|
||||
LocalDateTime tenantDateNow = tenantDateTime();
|
||||
LocalDateTime nextTriggerDate = smsCampaign.getNextTriggerDate();
|
||||
|
||||
logger.info("tenant time " + tenantDateNow.toString() + " trigger time " + nextTriggerDate.toString() + JobName.UPDATE_SMS_OUTBOUND_WITH_CAMPAIGN_MESSAGE.name());
|
||||
if (nextTriggerDate.isBefore(tenantDateNow)) {
|
||||
insertDirectCampaignIntoSmsOutboundTable(smsCampaign);
|
||||
this.updateTriggerDates(smsCampaign.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) {
|
||||
final Throwable realCause = dve.getMostSpecificCause();
|
||||
|
||||
throw new PlatformDataIntegrityException("error.msg.sms.campaign.unknown.data.integrity.issue",
|
||||
"Unknown data integrity issue with resource: " + realCause.getMessage());
|
||||
}
|
||||
|
||||
private LocalDateTime tenantDateTime() {
|
||||
LocalDateTime today = new LocalDateTime();
|
||||
final FineractPlatformTenant tenant = ThreadLocalContextUtil.getTenant();
|
||||
|
||||
if (tenant != null) {
|
||||
final DateTimeZone zone = DateTimeZone.forID(tenant.getTimezoneId());
|
||||
if (zone != null) {
|
||||
today = new LocalDateTime(zone);
|
||||
}
|
||||
}
|
||||
return today;
|
||||
}
|
||||
|
||||
// private String formatDestinationPhoneNumber(String phoneNumber, String countryCallingCode) {
|
||||
// StringBuilder formatedPhoneNumber = new StringBuilder("+");
|
||||
//
|
||||
// try {
|
||||
// Long phoneNumberToLong = Long.parseLong(phoneNumber);
|
||||
// Long countryCallingCodeToLong = Long.parseLong(countryCallingCode);
|
||||
// formatedPhoneNumber.append(Long.toString(countryCallingCodeToLong));
|
||||
// formatedPhoneNumber.append(Long.toString(phoneNumberToLong));
|
||||
// }
|
||||
//
|
||||
// catch (Exception e) {
|
||||
// logger.error("Invalid phone number or country calling code, must contain only numbers", e);
|
||||
// }
|
||||
//
|
||||
// return formatedPhoneNumber.toString();
|
||||
// }
|
||||
}
|
||||
+6
@@ -25,6 +25,7 @@ import java.util.Set;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.fineract.infrastructure.configuration.exception.ExternalServiceConfigurationNotFoundException;
|
||||
import org.apache.fineract.infrastructure.configuration.service.ExternalServicesConstants.S3_JSON_INPUT_PARAMS;
|
||||
import org.apache.fineract.infrastructure.configuration.service.ExternalServicesConstants.SMS_JSON_INPUT_PARAMS;
|
||||
import org.apache.fineract.infrastructure.configuration.service.ExternalServicesConstants.SMTP_JSON_INPUT_PARAMS;
|
||||
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
@@ -38,6 +39,7 @@ public class ExternalServicesPropertiesCommandFromApiJsonDeserializer {
|
||||
|
||||
private final Set<String> S3SupportedParameters = S3_JSON_INPUT_PARAMS.getAllValues();
|
||||
private final Set<String> SMTPSupportedParameters = SMTP_JSON_INPUT_PARAMS.getAllValues();
|
||||
private final Set<String> SMSSupportedParameters = SMS_JSON_INPUT_PARAMS.getAllValues();
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Autowired
|
||||
@@ -58,6 +60,10 @@ public class ExternalServicesPropertiesCommandFromApiJsonDeserializer {
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.SMTPSupportedParameters);
|
||||
break;
|
||||
|
||||
case "SMS":
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.SMSSupportedParameters);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ExternalServiceConfigurationNotFoundException(externalServiceName);
|
||||
}
|
||||
|
||||
+37
@@ -35,6 +35,12 @@ public class ExternalServicesConstants {
|
||||
public static final String SMTP_PORT = "port";
|
||||
public static final String SMTP_USE_TLS = "useTLS";
|
||||
|
||||
public static final String SMS_SERVICE_NAME = "MESSAGE_GATEWAY";
|
||||
public static final String SMS_HOST = "host_name";
|
||||
public static final String SMS_PORT = "port_number";
|
||||
public static final String SMS_END_POINT = "end_point";
|
||||
public static final String SMS_TENANT_APP_KEY = "tenant_app_key";
|
||||
|
||||
public static enum EXTERNALSERVICEPROPERTIES_JSON_INPUT_PARAMS {
|
||||
EXTERNAL_SERVICE_ID("external_service_id"), NAME("name"), VALUE("value");
|
||||
|
||||
@@ -96,6 +102,37 @@ public class ExternalServicesConstants {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum SMS_JSON_INPUT_PARAMS {
|
||||
HASTNAME("host_name"), PORT("port_number"), END_POINT("end_point"), TENANT_APP_KEY("tenant_app_key");
|
||||
|
||||
private final String value;
|
||||
|
||||
private SMS_JSON_INPUT_PARAMS(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private static final Set<String> values = new HashSet<>();
|
||||
|
||||
static {
|
||||
for (final SMS_JSON_INPUT_PARAMS type : SMS_JSON_INPUT_PARAMS.values()) {
|
||||
values.add(type.value);
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<String> getAllValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toString().replaceAll("_", " ");
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum S3_JSON_INPUT_PARAMS {
|
||||
S3_ACCESS_KEY("s3_access_key"), S3_BUCKET_NAME("s3_bucket_name"), S3_SECRET_KEY("s3_secret_key");
|
||||
|
||||
+3
@@ -20,6 +20,7 @@ package org.apache.fineract.infrastructure.configuration.service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.data.MessageGatewayConfigurationData;
|
||||
import org.apache.fineract.infrastructure.configuration.data.ExternalServicesPropertiesData;
|
||||
import org.apache.fineract.infrastructure.configuration.data.S3CredentialsData;
|
||||
import org.apache.fineract.infrastructure.configuration.data.SMTPCredentialsData;
|
||||
@@ -30,6 +31,8 @@ public interface ExternalServicesPropertiesReadPlatformService {
|
||||
|
||||
SMTPCredentialsData getSMTPCredentials();
|
||||
|
||||
MessageGatewayConfigurationData getSMSGateway();
|
||||
|
||||
Collection<ExternalServicesPropertiesData> retrieveOne(String serviceName);
|
||||
|
||||
}
|
||||
+39
@@ -22,6 +22,7 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.data.MessageGatewayConfigurationData;
|
||||
import org.apache.fineract.infrastructure.configuration.data.ExternalServicesPropertiesData;
|
||||
import org.apache.fineract.infrastructure.configuration.data.S3CredentialsData;
|
||||
import org.apache.fineract.infrastructure.configuration.data.SMTPCredentialsData;
|
||||
@@ -107,6 +108,30 @@ public class ExternalServicesPropertiesReadPlatformServiceImpl implements Extern
|
||||
|
||||
}
|
||||
|
||||
private static final class MessageGatewayDataExtractor implements ResultSetExtractor<MessageGatewayConfigurationData> {
|
||||
|
||||
@Override
|
||||
public MessageGatewayConfigurationData extractData(final ResultSet rs) throws SQLException, DataAccessException {
|
||||
String host = null;
|
||||
int port = 9191;
|
||||
String endPoint = null;
|
||||
String tenantAppKey = null;
|
||||
|
||||
while (rs.next()) {
|
||||
if (rs.getString("name").equalsIgnoreCase(ExternalServicesConstants.SMS_HOST)) {
|
||||
host = rs.getString("value");
|
||||
} else if (rs.getString("name").equalsIgnoreCase(ExternalServicesConstants.SMS_PORT)) {
|
||||
port = rs.getInt("value");
|
||||
} else if (rs.getString("name").equalsIgnoreCase(ExternalServicesConstants.SMS_END_POINT)) {
|
||||
endPoint = rs.getString("value");
|
||||
} else if (rs.getString("name").equalsIgnoreCase(ExternalServicesConstants.SMS_TENANT_APP_KEY)) {
|
||||
tenantAppKey = rs.getString("value");
|
||||
}
|
||||
}
|
||||
return new MessageGatewayConfigurationData(null, null, host, port, endPoint, null, null, false, tenantAppKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public S3CredentialsData getS3Credentials() {
|
||||
final ResultSetExtractor<S3CredentialsData> resultSetExtractor = new S3CredentialsDataExtractor();
|
||||
@@ -126,6 +151,15 @@ public class ExternalServicesPropertiesReadPlatformServiceImpl implements Extern
|
||||
return smtpCredentialsData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageGatewayConfigurationData getSMSGateway() {
|
||||
final ResultSetExtractor<MessageGatewayConfigurationData> resultSetExtractor = new MessageGatewayDataExtractor();
|
||||
final String sql = "SELECT esp.name, esp.value FROM c_external_service_properties esp inner join c_external_service es on esp.external_service_id = es.id where es.name = '"
|
||||
+ ExternalServicesConstants.SMS_SERVICE_NAME + "'";
|
||||
final MessageGatewayConfigurationData messageGatewayConfigurationData = this.jdbcTemplate.query(sql, resultSetExtractor, new Object[] {});
|
||||
return messageGatewayConfigurationData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ExternalServicesPropertiesData> retrieveOne(String serviceName) {
|
||||
String serviceNameToUse = null;
|
||||
@@ -138,6 +172,10 @@ public class ExternalServicesPropertiesReadPlatformServiceImpl implements Extern
|
||||
serviceNameToUse = ExternalServicesConstants.SMTP_SERVICE_NAME;
|
||||
break;
|
||||
|
||||
case "SMS":
|
||||
serviceNameToUse = ExternalServicesConstants.SMS_SERVICE_NAME;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ExternalServiceConfigurationNotFoundException(serviceName);
|
||||
}
|
||||
@@ -147,4 +185,5 @@ public class ExternalServicesPropertiesReadPlatformServiceImpl implements Extern
|
||||
return this.jdbcTemplate.query(sql, mapper, new Object[] {});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
@@ -54,6 +54,10 @@ public class ExternalServicesReadPlatformServiceImpl implements ExternalServices
|
||||
serviceNameToUse = ExternalServicesConstants.SMTP_SERVICE_NAME;
|
||||
break;
|
||||
|
||||
case "SMS":
|
||||
serviceNameToUse = ExternalServicesConstants.SMS_SERVICE_NAME;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ExternalServiceConfigurationNotFoundException(serviceName);
|
||||
}
|
||||
|
||||
+4
@@ -270,6 +270,10 @@ public class FromJsonHelper {
|
||||
return this.helperDelegator.extractMonthDayFormatParameter(element);
|
||||
}
|
||||
|
||||
public JsonObject extractJsonObjectNamed(final String parameterName, final JsonElement element) {
|
||||
return this.helperDelegator.extractJsonObjectNamed(parameterName, element);
|
||||
}
|
||||
|
||||
public Gson getGsonConverter() {
|
||||
return this.gsonConverter;
|
||||
}
|
||||
|
||||
+13
@@ -271,6 +271,19 @@ public class JsonParserHelper {
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
public JsonObject extractJsonObjectNamed(final String parameterName, final JsonElement element) {
|
||||
JsonObject jsonObject = null;
|
||||
|
||||
if (element.isJsonObject()) {
|
||||
final JsonObject object = element.getAsJsonObject();
|
||||
if (object.has(parameterName)) {
|
||||
jsonObject = object.get(parameterName).getAsJsonObject();
|
||||
}
|
||||
}
|
||||
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used with the local date is in array format
|
||||
*/
|
||||
|
||||
+10
@@ -36,4 +36,14 @@ public class PaginationHelper<E> {
|
||||
|
||||
return new Page<>(items, totalFilteredRecords);
|
||||
}
|
||||
|
||||
public Page<Long> fetchPage(JdbcTemplate jdbcTemplate, String sql, String sqlCountRows, Class<Long> type) {
|
||||
final List<Long> items = jdbcTemplate.queryForList(sql, type);
|
||||
|
||||
// determine how many rows are available
|
||||
@SuppressWarnings("deprecation")
|
||||
final int totalFilteredRecords = jdbcTemplate.queryForInt(sqlCountRows);
|
||||
|
||||
return new Page<>(items, totalFilteredRecords);
|
||||
}
|
||||
}
|
||||
+16
@@ -209,6 +209,22 @@ public final class SearchParameters {
|
||||
staffId, accountNo, loanId, savingsId, orphansOnly, isSelfUser);
|
||||
}
|
||||
|
||||
public static SearchParameters forSMSCampaign(final String sqlSearch, final Integer offset, final Integer limit, final String orderBy,
|
||||
final String sortOrder) {
|
||||
|
||||
final String externalId = null;
|
||||
final Integer maxLimitAllowed = getCheckedLimit(limit);
|
||||
final Long staffId = null;
|
||||
final String accountNo = null;
|
||||
final Long loanId = null;
|
||||
final Long savingsId = null;
|
||||
final Boolean orphansOnly = false;
|
||||
final boolean isSelfUser = false;
|
||||
|
||||
return new SearchParameters(sqlSearch, null, externalId, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder,
|
||||
staffId, accountNo, loanId, savingsId, orphansOnly, isSelfUser);
|
||||
}
|
||||
|
||||
private SearchParameters(final String sqlSearch, final Long officeId, final String externalId, final String name,
|
||||
final String hierarchy, final String firstname, final String lastname, final Integer offset, final Integer limit,
|
||||
final String orderBy, final String sortOrder, final Long staffId, final String accountNo, final Long loanId,
|
||||
|
||||
+5
@@ -44,4 +44,9 @@ public interface ReadReportingService {
|
||||
ReportData retrieveReport(final Long id);
|
||||
|
||||
Collection<String> getAllowedReportTypes();
|
||||
|
||||
//needed for smsCampaign jobs where securityContext is null
|
||||
GenericResultsetData retrieveGenericResultSetForSmsCampaign(String name, String type, Map<String, String> extractedQueryParams);
|
||||
|
||||
String sqlToRunForSmsCampaign(String name, String type, Map<String, String> queryParams);
|
||||
}
|
||||
+31
@@ -484,4 +484,35 @@ public class ReadReportingServiceImpl implements ReadReportingService {
|
||||
return new ReportParameterData(id, null, null, parameterName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericResultsetData retrieveGenericResultSetForSmsCampaign(String name, String type, Map<String, String> queryParams) {
|
||||
final long startTime = System.currentTimeMillis();
|
||||
logger.info("STARTING REPORT: " + name + " Type: " + type);
|
||||
|
||||
final String sql = sqlToRunForSmsCampaign(name, type, queryParams);
|
||||
|
||||
final GenericResultsetData result = this.genericDataService.fillGenericResultSet(sql);
|
||||
|
||||
final long elapsed = System.currentTimeMillis() - startTime;
|
||||
logger.info("FINISHING Report/Request Name: " + name + " - " + type + " Elapsed Time: " + elapsed);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sqlToRunForSmsCampaign(final String name, final String type, final Map<String, String> queryParams) {
|
||||
String sql = getSql(name, type);
|
||||
|
||||
final Set<String> keys = queryParams.keySet();
|
||||
for (String key : keys) {
|
||||
final String pValue = queryParams.get(key);
|
||||
// logger.info("(" + key + " : " + pValue + ")");
|
||||
key = "${" + key + "}";
|
||||
sql = this.genericDataService.replace(sql, key, pValue);
|
||||
}
|
||||
|
||||
sql = this.genericDataService.wrapSQL(sql);
|
||||
|
||||
return sql;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -42,7 +42,10 @@ public enum JobName {
|
||||
POST_DIVIDENTS_FOR_SHARES("Post Dividends For Shares"), //
|
||||
UPDATE_SAVINGS_DORMANT_ACCOUNTS("Update Savings Dormant Accounts"), //
|
||||
ADD_PERIODIC_ACCRUAL_ENTRIES_FOR_LOANS_WITH_INCOME_POSTED_AS_TRANSACTIONS("Add Accrual Transactions For Loans With Income Posted As Transactions"),
|
||||
EXECUTE_REPORT_MAILING_JOBS("Execute Report Mailing Jobs");
|
||||
EXECUTE_REPORT_MAILING_JOBS("Execute Report Mailing Jobs"),
|
||||
UPDATE_SMS_OUTBOUND_WITH_CAMPAIGN_MESSAGE("Update Sms Outbound with campaign message"),
|
||||
SEND_MESSAGES_TO_SMS_GATEWAY("Send messages to SMS gateway"),
|
||||
GET_DELIVERY_REPORTS_FROM_SMS_GATEWAY("Get delivery reports from SMS gateway");
|
||||
|
||||
private final String name;
|
||||
|
||||
|
||||
+3
-2
@@ -36,13 +36,14 @@ public class SmsApiConstants {
|
||||
public static final String clientIdParamName = "clientId";
|
||||
public static final String staffIdParamName = "staffId";
|
||||
public static final String messageParamName = "message";
|
||||
public static final String campaignIdParamName = "campaignId";
|
||||
|
||||
// response parameters
|
||||
public static final String statusParamName = "status";
|
||||
|
||||
public static final Set<String> CREATE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
|
||||
dateFormatParamName, groupIdParamName, clientIdParamName, staffIdParamName, messageParamName));
|
||||
dateFormatParamName, groupIdParamName, clientIdParamName, staffIdParamName, messageParamName, campaignIdParamName));
|
||||
|
||||
public static final Set<String> UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(messageParamName));
|
||||
public static final Set<String> UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(messageParamName, campaignIdParamName));
|
||||
|
||||
}
|
||||
+34
@@ -19,6 +19,7 @@
|
||||
package org.apache.fineract.infrastructure.sms.api;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
@@ -28,10 +29,12 @@ import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.apache.fineract.accounting.journalentry.api.DateParam;
|
||||
import org.apache.fineract.commands.domain.CommandWrapper;
|
||||
import org.apache.fineract.commands.service.CommandWrapperBuilder;
|
||||
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
@@ -39,6 +42,8 @@ import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.apache.fineract.infrastructure.core.service.Page;
|
||||
import org.apache.fineract.infrastructure.core.service.SearchParameters;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.infrastructure.sms.data.SmsData;
|
||||
import org.apache.fineract.infrastructure.sms.service.SmsReadPlatformService;
|
||||
@@ -103,6 +108,35 @@ public class SmsApiResource {
|
||||
return this.toApiJsonSerializer.serialize(settings, smsMessage);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{campaignId}/messageByStatus")
|
||||
public String retrieveAllSmsByStatus(@PathParam("campaignId") final Long campaignId, @Context final UriInfo uriInfo,
|
||||
@QueryParam("status") final Long status, @QueryParam("fromDate") final DateParam fromDateParam,
|
||||
@QueryParam("toDate") final DateParam toDateParam, @QueryParam("locale") final String locale,
|
||||
@QueryParam("dateFormat") final String dateFormat, @QueryParam("sqlSearch") final String sqlSearch,
|
||||
@QueryParam("offset") final Integer offset, @QueryParam("limit") final Integer limit,
|
||||
@QueryParam("orderBy") final String orderBy, @QueryParam("sortOrder") final String sortOrder) {
|
||||
|
||||
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
|
||||
|
||||
final SearchParameters searchParameters = SearchParameters.forSMSCampaign(sqlSearch, offset, limit, orderBy, sortOrder);
|
||||
|
||||
Date fromDate = null;
|
||||
if (fromDateParam != null) {
|
||||
fromDate = fromDateParam.getDate("fromDate", dateFormat, locale);
|
||||
}
|
||||
Date toDate = null;
|
||||
if (toDateParam != null) {
|
||||
toDate = toDateParam.getDate("toDate", dateFormat, locale);
|
||||
}
|
||||
|
||||
final Page<SmsData> smsMessages = this.readPlatformService.retrieveSmsByStatus(campaignId, searchParameters, status.intValue(), fromDate,
|
||||
toDate);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, smsMessages);
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("{resourceId}")
|
||||
public String update(@PathParam("resourceId") final Long resourceId, final String apiRequestBodyAsJson) {
|
||||
|
||||
+44
-10
@@ -25,28 +25,23 @@ import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
*/
|
||||
public class SmsData {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Long id;
|
||||
@SuppressWarnings("unused")
|
||||
private final Long groupId;
|
||||
@SuppressWarnings("unused")
|
||||
private final Long clientId;
|
||||
@SuppressWarnings("unused")
|
||||
private final Long staffId;
|
||||
@SuppressWarnings("unused")
|
||||
private final EnumOptionData status;
|
||||
@SuppressWarnings("unused")
|
||||
private final String mobileNo;
|
||||
@SuppressWarnings("unused")
|
||||
private final String message;
|
||||
private final Long providerId;
|
||||
private final String campaignName;
|
||||
|
||||
public static SmsData instance(final Long id, final Long groupId, final Long clientId, final Long staffId, final EnumOptionData status,
|
||||
final String mobileNo, final String message) {
|
||||
return new SmsData(id, groupId, clientId, staffId, status, mobileNo, message);
|
||||
final String mobileNo, final String message, final Long providerId, final String camapignName) {
|
||||
return new SmsData(id, groupId, clientId, staffId, status, mobileNo, message, providerId, camapignName);
|
||||
}
|
||||
|
||||
private SmsData(final Long id, final Long groupId, final Long clientId, final Long staffId, final EnumOptionData status,
|
||||
final String mobileNo, final String message) {
|
||||
final String mobileNo, final String message, final Long providerId, final String camapignName) {
|
||||
this.id = id;
|
||||
this.groupId = groupId;
|
||||
this.clientId = clientId;
|
||||
@@ -54,5 +49,44 @@ public class SmsData {
|
||||
this.status = status;
|
||||
this.mobileNo = mobileNo;
|
||||
this.message = message;
|
||||
this.providerId = providerId;
|
||||
this.campaignName = camapignName;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public Long getGroupId() {
|
||||
return this.groupId;
|
||||
}
|
||||
|
||||
public Long getClientId() {
|
||||
return this.clientId;
|
||||
}
|
||||
|
||||
public Long getStaffId() {
|
||||
return this.staffId;
|
||||
}
|
||||
|
||||
public EnumOptionData getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
public String getMobileNo() {
|
||||
return this.mobileNo;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return this.message;
|
||||
}
|
||||
|
||||
public Long getProviderId() {
|
||||
return this.providerId;
|
||||
}
|
||||
|
||||
public String getCampaignName() {
|
||||
return this.campaignName;
|
||||
}
|
||||
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* 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.sms.data;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* Immutable data object representing the API request body sent in the POST
|
||||
* request to the "/queue" resource
|
||||
**/
|
||||
public class SmsMessageApiQueueResourceData {
|
||||
|
||||
private Long internalId;
|
||||
private String tenantId;
|
||||
private String createdOnDate;
|
||||
private String sourceAddress;
|
||||
private String mobileNumber;
|
||||
private String message;
|
||||
private Long providerId;
|
||||
|
||||
/**
|
||||
* SmsMessageApiQueueResourceData constructor
|
||||
**/
|
||||
private SmsMessageApiQueueResourceData(Long internalId, String mifosTenantIdentifier, String createdOnDate, String sourceAddress,
|
||||
String mobileNumber, String message, Long providerId) {
|
||||
this.internalId = internalId;
|
||||
this.tenantId = mifosTenantIdentifier;
|
||||
this.createdOnDate = createdOnDate;
|
||||
this.sourceAddress = sourceAddress;
|
||||
this.mobileNumber = mobileNumber;
|
||||
this.message = message;
|
||||
this.providerId = providerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* SmsMessageApiQueueResourceData constructor
|
||||
**/
|
||||
protected SmsMessageApiQueueResourceData() {}
|
||||
|
||||
/**
|
||||
* @return a new instance of the SmsMessageApiQueueResourceData class
|
||||
**/
|
||||
public static final SmsMessageApiQueueResourceData instance(Long internalId, String mifosTenantIdentifier, String createdOnDate,
|
||||
String sourceAddress, String mobileNumber, String message, Long providerId) {
|
||||
|
||||
return new SmsMessageApiQueueResourceData(internalId, mifosTenantIdentifier, createdOnDate, sourceAddress, mobileNumber, message,
|
||||
providerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internalId
|
||||
*/
|
||||
public Long getInternalId() {
|
||||
return internalId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the mifosTenantIdentifier
|
||||
*/
|
||||
public String getTenantId() {
|
||||
return tenantId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the createdOnDate
|
||||
*/
|
||||
public String getCreatedOnDate() {
|
||||
return createdOnDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the sourceAddress
|
||||
*/
|
||||
public String getSourceAddress() {
|
||||
return sourceAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the mobileNumber
|
||||
*/
|
||||
public String getMobileNumber() {
|
||||
return mobileNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the message
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the providerId
|
||||
*/
|
||||
public Long getproviderId() {
|
||||
return providerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JSON representation of the object
|
||||
**/
|
||||
public static String toJsonString(Collection<SmsMessageApiQueueResourceData> smsResourceData) {
|
||||
Gson gson = new Gson();
|
||||
|
||||
return gson.toJson(smsResourceData);
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* 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.sms.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* Immutable data object representing the API request body sent in the POST request to
|
||||
* the "/report" resource
|
||||
**/
|
||||
public class SmsMessageApiReportResourceData {
|
||||
private List<Long> externalIds;
|
||||
private String mifosTenantIdentifier;
|
||||
|
||||
/**
|
||||
* SmsMessageApiReportResourceData constructor
|
||||
**/
|
||||
private SmsMessageApiReportResourceData(List<Long> externalIds, String mifosTenantIdentifier) {
|
||||
this.externalIds = externalIds;
|
||||
this.mifosTenantIdentifier = mifosTenantIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* SmsMessageApiReportResourceData constructor
|
||||
**/
|
||||
protected SmsMessageApiReportResourceData() {}
|
||||
|
||||
/**
|
||||
* @return new instance of the SmsMessageApiReportResourceData class
|
||||
**/
|
||||
public static final SmsMessageApiReportResourceData instance(List<Long> externalIds, String mifosTenantIdentifier) {
|
||||
return new SmsMessageApiReportResourceData(externalIds, mifosTenantIdentifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the externalIds
|
||||
*/
|
||||
public List<Long> getExternalIds() {
|
||||
return externalIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the mifosTenantIdentifier
|
||||
*/
|
||||
public String getMifosTenantIdentifier() {
|
||||
return mifosTenantIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JSON representation of the object
|
||||
**/
|
||||
public String toJsonString() {
|
||||
Gson gson = new Gson();
|
||||
|
||||
return gson.toJson(this);
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* 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.sms.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Immutable data object representing an outbound SMS message API response data
|
||||
**/
|
||||
public class SmsMessageApiResponseData {
|
||||
private Integer httpStatusCode;
|
||||
private List<SmsMessageDeliveryReportData> data;
|
||||
|
||||
/**
|
||||
* SmsMessageApiResponseData constructor
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
private SmsMessageApiResponseData(Integer httpStatusCode, List<SmsMessageDeliveryReportData> data) {
|
||||
this.httpStatusCode = httpStatusCode;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default SmsMessageApiResponseData constructor
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
protected SmsMessageApiResponseData() {}
|
||||
|
||||
/**
|
||||
* @return an instance of the SmsMessageApiResponseData class
|
||||
**/
|
||||
public static SmsMessageApiResponseData getInstance(Integer httpStatusCode, List<SmsMessageDeliveryReportData> data) {
|
||||
return new SmsMessageApiResponseData(httpStatusCode, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the httpStatusCode
|
||||
*/
|
||||
public Integer getHttpStatusCode() {
|
||||
return httpStatusCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the data
|
||||
*/
|
||||
public List<SmsMessageDeliveryReportData> getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* 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.sms.data;
|
||||
|
||||
/**
|
||||
* Immutable data object representing an outbound SMS message delivery report data
|
||||
**/
|
||||
public class SmsMessageDeliveryReportData {
|
||||
private Long id;
|
||||
private String externalId;
|
||||
private String addedOnDate;
|
||||
private String deliveredOnDate;
|
||||
private Integer deliveryStatus;
|
||||
private Boolean hasError;
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* SmsMessageDeliveryReportData constructor
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
private SmsMessageDeliveryReportData(Long id, String externalId, String addedOnDate, String deliveredOnDate,
|
||||
Integer deliveryStatus, Boolean hasError, String errorMessage) {
|
||||
this.id = id;
|
||||
this.externalId = externalId;
|
||||
this.addedOnDate = addedOnDate;
|
||||
this.deliveredOnDate = deliveredOnDate;
|
||||
this.deliveryStatus = deliveryStatus;
|
||||
this.hasError = hasError;
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default SmsMessageDeliveryReportData constructor
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
protected SmsMessageDeliveryReportData() {}
|
||||
|
||||
/**
|
||||
* @return an instance of the SmsMessageDeliveryReportData class
|
||||
**/
|
||||
public static SmsMessageDeliveryReportData getInstance(Long id, String externalId, String addedOnDate, String deliveredOnDate,
|
||||
Integer deliveryStatus, Boolean hasError, String errorMessage) {
|
||||
|
||||
return new SmsMessageDeliveryReportData(id, externalId, addedOnDate, deliveredOnDate, deliveryStatus, hasError, errorMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the externalId
|
||||
*/
|
||||
public String getExternalId() {
|
||||
return externalId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the addedOnDate
|
||||
*/
|
||||
public String getAddedOnDate() {
|
||||
return addedOnDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the deliveredOnDate
|
||||
*/
|
||||
public String getDeliveredOnDate() {
|
||||
return deliveredOnDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the deliveryStatus
|
||||
*/
|
||||
public Integer getDeliveryStatus() {
|
||||
return deliveryStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the hasError
|
||||
*/
|
||||
public Boolean getHasError() {
|
||||
return hasError;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the errorMessage
|
||||
*/
|
||||
public String getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
}
|
||||
+98
-6
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.sms.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -26,19 +27,26 @@ 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 org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.domain.SmsCampaign;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.infrastructure.sms.SmsApiConstants;
|
||||
import org.apache.fineract.organisation.staff.domain.Staff;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.group.domain.Group;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
@Entity
|
||||
@Table(name = "sms_messages_outbound")
|
||||
public class SmsMessage extends AbstractPersistableCustom<Long> {
|
||||
|
||||
@Column(name = "external_id", nullable = true)
|
||||
private Long externalId;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "group_id", nullable = true)
|
||||
private Group group;
|
||||
@@ -51,6 +59,10 @@ public class SmsMessage extends AbstractPersistableCustom<Long> {
|
||||
@JoinColumn(name = "staff_id", nullable = true)
|
||||
private Staff staff;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "campaign_id", nullable = false)
|
||||
private SmsCampaign smsCampaign;
|
||||
|
||||
@Column(name = "status_enum", nullable = false)
|
||||
private Integer statusType;
|
||||
|
||||
@@ -60,23 +72,51 @@ public class SmsMessage extends AbstractPersistableCustom<Long> {
|
||||
@Column(name = "message", nullable = false)
|
||||
private String message;
|
||||
|
||||
public static SmsMessage pendingSms(final Group group, final Client client, final Staff staff, final String message,
|
||||
final String mobileNo) {
|
||||
return new SmsMessage(group, client, staff, SmsMessageStatusType.PENDING, message, mobileNo);
|
||||
// @Column(name = "provider_id", nullable = true)
|
||||
// private Long providerId;
|
||||
//
|
||||
// @Column(name = "campaign_name", nullable = true)
|
||||
// private String campaignName;
|
||||
|
||||
@Column(name = "submittedon_date", nullable = true)
|
||||
@Temporal(TemporalType.DATE)
|
||||
private Date submittedOnDate;
|
||||
|
||||
@Column(name = "delivered_on_date", nullable = true)
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date deliveredOnDate;
|
||||
|
||||
public static SmsMessage pendingSms(final Long externalId, final Group group, final Client client, final Staff staff,
|
||||
final String message, final String mobileNo, final SmsCampaign smsCampaign) {
|
||||
return new SmsMessage(externalId, group, client, staff, SmsMessageStatusType.PENDING, message, mobileNo, smsCampaign);
|
||||
}
|
||||
|
||||
public static SmsMessage sentSms(final Long externalId, final Group group, final Client client, final Staff staff,
|
||||
final String message, final String mobileNo, final SmsCampaign smsCampaign) {
|
||||
return new SmsMessage(externalId, group, client, staff, SmsMessageStatusType.WAITING_FOR_DELIVERY_REPORT, message, mobileNo, smsCampaign);
|
||||
}
|
||||
|
||||
public static SmsMessage instance(Long externalId, final Group group, final Client client, final Staff staff,
|
||||
final SmsMessageStatusType statusType, final String message, final String mobileNo, final SmsCampaign smsCampaign) {
|
||||
|
||||
return new SmsMessage(externalId, group, client, staff, statusType, message, mobileNo, smsCampaign);
|
||||
}
|
||||
|
||||
protected SmsMessage() {
|
||||
//
|
||||
}
|
||||
|
||||
private SmsMessage(final Group group, final Client client, final Staff staff, final SmsMessageStatusType statusType,
|
||||
final String message, final String mobileNo) {
|
||||
private SmsMessage(Long externalId, final Group group, final Client client, final Staff staff, final SmsMessageStatusType statusType,
|
||||
final String message, final String mobileNo, final SmsCampaign smsCampaign) {
|
||||
this.externalId = externalId;
|
||||
this.group = group;
|
||||
this.client = client;
|
||||
this.staff = staff;
|
||||
this.statusType = statusType.getValue();
|
||||
this.mobileNo = mobileNo;
|
||||
this.message = message;
|
||||
this.smsCampaign = smsCampaign;
|
||||
this.submittedOnDate = LocalDate.now().toDate();
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command) {
|
||||
@@ -91,4 +131,56 @@ public class SmsMessage extends AbstractPersistableCustom<Long> {
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public Long getExternalId() {
|
||||
return this.externalId;
|
||||
}
|
||||
|
||||
public SmsCampaign getSmsCampaign() {
|
||||
return this.smsCampaign;
|
||||
}
|
||||
|
||||
public Group getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public Client getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public Staff getStaff() {
|
||||
return staff;
|
||||
}
|
||||
|
||||
public Integer getStatusType() {
|
||||
return statusType;
|
||||
}
|
||||
|
||||
public String getMobileNo() {
|
||||
return mobileNo;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setExternalId(final Long externalId) {
|
||||
this.externalId = externalId;
|
||||
}
|
||||
|
||||
public void setStatusType(final Integer statusType) {
|
||||
this.statusType = statusType;
|
||||
}
|
||||
|
||||
public Date getSubmittedOnDate() {
|
||||
return this.submittedOnDate;
|
||||
}
|
||||
|
||||
public Date getDeliveredOnDate() {
|
||||
return this.deliveredOnDate;
|
||||
}
|
||||
|
||||
public void setDeliveredOnDate(final Date deliveredOnDate) {
|
||||
this.deliveredOnDate = deliveredOnDate;
|
||||
}
|
||||
}
|
||||
+15
-3
@@ -18,6 +18,9 @@
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.sms.domain;
|
||||
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.domain.SmsCampaign;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.domain.SmsCampaignRepository;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.exception.SmsCampaignNotFound;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.infrastructure.sms.SmsApiConstants;
|
||||
@@ -40,17 +43,19 @@ public class SmsMessageAssembler {
|
||||
private final GroupRepositoryWrapper groupRepository;
|
||||
private final ClientRepositoryWrapper clientRepository;
|
||||
private final StaffRepositoryWrapper staffRepository;
|
||||
private final SmsCampaignRepository smsCampaignRepository;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Autowired
|
||||
public SmsMessageAssembler(final SmsMessageRepository smsMessageRepository, final GroupRepositoryWrapper groupRepositoryWrapper,
|
||||
final ClientRepositoryWrapper clientRepository, final StaffRepositoryWrapper staffRepository,
|
||||
final FromJsonHelper fromApiJsonHelper) {
|
||||
final FromJsonHelper fromApiJsonHelper, final SmsCampaignRepository smsCampaignRepository) {
|
||||
this.smsMessageRepository = smsMessageRepository;
|
||||
this.groupRepository = groupRepositoryWrapper;
|
||||
this.clientRepository = clientRepository;
|
||||
this.staffRepository = staffRepository;
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
this.smsCampaignRepository = smsCampaignRepository;
|
||||
}
|
||||
|
||||
public SmsMessage assembleFromJson(final JsonCommand command) {
|
||||
@@ -58,13 +63,20 @@ public class SmsMessageAssembler {
|
||||
final JsonElement element = command.parsedJson();
|
||||
|
||||
String mobileNo = null;
|
||||
|
||||
Group group = null;
|
||||
Long externalId = null;
|
||||
if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.groupIdParamName, element)) {
|
||||
final Long groupId = this.fromApiJsonHelper.extractLongNamed(SmsApiConstants.groupIdParamName, element);
|
||||
group = this.groupRepository.findOneWithNotFoundDetection(groupId);
|
||||
}
|
||||
|
||||
SmsCampaign smsCampaign = null;
|
||||
if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.campaignIdParamName, element)) {
|
||||
final Long campaignId = this.fromApiJsonHelper.extractLongNamed(SmsApiConstants.campaignIdParamName, element);
|
||||
smsCampaign = this.smsCampaignRepository.findOne(campaignId);
|
||||
if (smsCampaign == null) { throw new SmsCampaignNotFound(campaignId); }
|
||||
}
|
||||
|
||||
Client client = null;
|
||||
if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.clientIdParamName, element)) {
|
||||
final Long clientId = this.fromApiJsonHelper.extractLongNamed(SmsApiConstants.clientIdParamName, element);
|
||||
@@ -81,7 +93,7 @@ public class SmsMessageAssembler {
|
||||
|
||||
final String message = this.fromApiJsonHelper.extractStringNamed(SmsApiConstants.messageParamName, element);
|
||||
|
||||
return SmsMessage.pendingSms(group, client, staff, message, mobileNo);
|
||||
return SmsMessage.pendingSms(externalId, group, client, staff, message, mobileNo, smsCampaign);
|
||||
}
|
||||
|
||||
public SmsMessage assembleFromResourceId(final Long resourceId) {
|
||||
|
||||
+4
-1
@@ -18,9 +18,12 @@
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.sms.domain;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
public interface SmsMessageRepository extends JpaRepository<SmsMessage, Long>, JpaSpecificationExecutor<SmsMessage> {
|
||||
// no extra behaviour
|
||||
|
||||
Page<SmsMessage> findByStatusType(final Integer status, Pageable pageable);
|
||||
}
|
||||
+4
@@ -22,6 +22,7 @@ public enum SmsMessageStatusType {
|
||||
|
||||
INVALID(0, "smsMessageStatusType.invalid"), //
|
||||
PENDING(100, "smsMessageStatusType.pending"), //
|
||||
WAITING_FOR_DELIVERY_REPORT(150, "smsMessageStatusType.waitingForDeliveryReport"),
|
||||
SENT(200, "smsMessageStatusType.sent"), //
|
||||
DELIVERED(300, "smsMessageStatusType.delivered"), //
|
||||
FAILED(400, "smsMessageStatusType.failed");
|
||||
@@ -36,6 +37,9 @@ public enum SmsMessageStatusType {
|
||||
case 100:
|
||||
enumeration = SmsMessageStatusType.PENDING;
|
||||
break;
|
||||
case 150:
|
||||
enumeration = SmsMessageStatusType.WAITING_FOR_DELIVERY_REPORT;
|
||||
break;
|
||||
case 200:
|
||||
enumeration = SmsMessageStatusType.SENT;
|
||||
break;
|
||||
|
||||
+28
@@ -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.sms.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
|
||||
public class SmsCountryCodeNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||
|
||||
public SmsCountryCodeNotFoundException() {
|
||||
super("error.msg.sms.country.code.not.found", "SMS country code does not exist");
|
||||
}
|
||||
}
|
||||
+47
@@ -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.sms.scheduler;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.domain.SmsCampaign;
|
||||
import org.apache.fineract.infrastructure.sms.domain.SmsMessage;
|
||||
|
||||
/**
|
||||
* Scheduled Job service interface for SMS message
|
||||
**/
|
||||
public interface SmsMessageScheduledJobService {
|
||||
|
||||
/**
|
||||
* sends a batch of SMS messages to the SMS gateway
|
||||
**/
|
||||
public void sendMessagesToGateway();
|
||||
|
||||
/**
|
||||
* sends triggered batch SMS messages to SMS gateway
|
||||
* @param smsDataMap
|
||||
*/
|
||||
public void sendTriggeredMessages(Map<SmsCampaign, Collection<SmsMessage>> smsDataMap);
|
||||
|
||||
/**
|
||||
* get delivery report from the SMS gateway
|
||||
**/
|
||||
public void getDeliveryReports();
|
||||
}
|
||||
+295
@@ -0,0 +1,295 @@
|
||||
/**
|
||||
* 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.sms.scheduler;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.apache.fineract.infrastructure.campaigns.helper.SmsConfigUtils;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignConstants;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.domain.SmsCampaign;
|
||||
import org.apache.fineract.infrastructure.campaigns.sms.exception.ConnectionFailureException;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||
import org.apache.fineract.infrastructure.core.service.Page;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.infrastructure.jobs.annotation.CronTarget;
|
||||
import org.apache.fineract.infrastructure.jobs.service.JobName;
|
||||
import org.apache.fineract.infrastructure.sms.data.SmsMessageApiQueueResourceData;
|
||||
import org.apache.fineract.infrastructure.sms.data.SmsMessageDeliveryReportData;
|
||||
import org.apache.fineract.infrastructure.sms.domain.SmsMessage;
|
||||
import org.apache.fineract.infrastructure.sms.domain.SmsMessageRepository;
|
||||
import org.apache.fineract.infrastructure.sms.domain.SmsMessageStatusType;
|
||||
import org.apache.fineract.infrastructure.sms.service.SmsReadPlatformService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextClosedEvent;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* Scheduled job services that send SMS messages and get delivery reports for
|
||||
* the sent SMS messages
|
||||
**/
|
||||
@Service
|
||||
public class SmsMessageScheduledJobServiceImpl implements SmsMessageScheduledJobService {
|
||||
|
||||
private final SmsMessageRepository smsMessageRepository;
|
||||
private final SmsReadPlatformService smsReadPlatformService;
|
||||
private static final Logger logger = LoggerFactory.getLogger(SmsMessageScheduledJobServiceImpl.class);
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
private ExecutorService genericExecutorService ;
|
||||
private ExecutorService triggeredExecutorService ;
|
||||
private final SmsConfigUtils smsConfigUtils ;
|
||||
|
||||
|
||||
/**
|
||||
* SmsMessageScheduledJobServiceImpl constructor
|
||||
**/
|
||||
@Autowired
|
||||
public SmsMessageScheduledJobServiceImpl(SmsMessageRepository smsMessageRepository, SmsReadPlatformService smsReadPlatformService,
|
||||
final SmsConfigUtils smsConfigUtils) {
|
||||
this.smsMessageRepository = smsMessageRepository;
|
||||
this.smsReadPlatformService = smsReadPlatformService;
|
||||
this.smsConfigUtils = smsConfigUtils ;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void initializeExecutorService() {
|
||||
genericExecutorService = Executors.newSingleThreadExecutor();
|
||||
triggeredExecutorService = Executors.newSingleThreadExecutor() ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send batches of SMS messages to the SMS gateway (or intermediate gateway)
|
||||
**/
|
||||
@Override
|
||||
@Transactional
|
||||
@CronTarget(jobName = JobName.SEND_MESSAGES_TO_SMS_GATEWAY)
|
||||
public void sendMessagesToGateway() {
|
||||
Integer pageLimit = 200;
|
||||
Integer page = 0;
|
||||
int totalRecords = 0;
|
||||
do {
|
||||
PageRequest pageRequest = new PageRequest(0, pageLimit);
|
||||
org.springframework.data.domain.Page<SmsMessage> pendingMessages = this.smsMessageRepository.findByStatusType(
|
||||
SmsMessageStatusType.PENDING.getValue(), pageRequest);
|
||||
List<SmsMessage> toSaveMessages = new ArrayList<>() ;
|
||||
try {
|
||||
|
||||
if (pendingMessages.getContent().size() > 0) {
|
||||
final String tenantIdentifier = ThreadLocalContextUtil.getTenant().getTenantIdentifier();
|
||||
Iterator<SmsMessage> pendingMessageIterator = pendingMessages.iterator();
|
||||
Collection<SmsMessageApiQueueResourceData> apiQueueResourceDatas = new ArrayList<>();
|
||||
while (pendingMessageIterator.hasNext()) {
|
||||
SmsMessage smsData = pendingMessageIterator.next();
|
||||
|
||||
SmsMessageApiQueueResourceData apiQueueResourceData = SmsMessageApiQueueResourceData.instance(smsData.getId(),
|
||||
tenantIdentifier, null, null, smsData.getMobileNo(), smsData.getMessage(), smsData.getSmsCampaign()
|
||||
.getProviderId());
|
||||
apiQueueResourceDatas.add(apiQueueResourceData);
|
||||
smsData.setStatusType(SmsMessageStatusType.WAITING_FOR_DELIVERY_REPORT.getValue());
|
||||
toSaveMessages.add(smsData) ;
|
||||
}
|
||||
this.smsMessageRepository.save(toSaveMessages);
|
||||
this.smsMessageRepository.flush();
|
||||
this.genericExecutorService.execute(new SmsTask(ThreadLocalContextUtil.getTenant(), apiQueueResourceDatas));
|
||||
|
||||
// new MyThread(ThreadLocalContextUtil.getTenant(), apiQueueResourceDatas).start();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ConnectionFailureException(SmsCampaignConstants.SMS);
|
||||
}
|
||||
page ++;
|
||||
totalRecords = pendingMessages.getTotalPages();
|
||||
} while (page < totalRecords);
|
||||
}
|
||||
|
||||
class SmsTask implements Runnable, ApplicationListener<ContextClosedEvent> {
|
||||
|
||||
private final FineractPlatformTenant tenant;
|
||||
private final Collection<SmsMessageApiQueueResourceData> apiQueueResourceDatas;
|
||||
|
||||
public SmsTask(final FineractPlatformTenant tenant, final Collection<SmsMessageApiQueueResourceData> apiQueueResourceDatas) {
|
||||
this.tenant = tenant;
|
||||
this.apiQueueResourceDatas = apiQueueResourceDatas;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ThreadLocalContextUtil.setTenant(tenant);
|
||||
connectAndSendToIntermediateServer(tenant.getTenantIdentifier(), apiQueueResourceDatas);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextClosedEvent event) {
|
||||
genericExecutorService.shutdown();
|
||||
logger.info("Shutting down the ExecutorService");
|
||||
}
|
||||
}
|
||||
|
||||
private void connectAndSendToIntermediateServer(String tenantIdentifier,
|
||||
Collection<SmsMessageApiQueueResourceData> apiQueueResourceDatas) {
|
||||
Map<String, Object> hostConfig = this.smsConfigUtils.getMessageGateWayRequestURI("sms", SmsMessageApiQueueResourceData.toJsonString(apiQueueResourceDatas)) ;
|
||||
URI uri = (URI)hostConfig.get("uri") ;
|
||||
HttpEntity<?> entity = (HttpEntity<?>)hostConfig.get("entity") ;
|
||||
ResponseEntity<String> responseOne = restTemplate.exchange(uri, HttpMethod.POST, entity,
|
||||
new ParameterizedTypeReference<String>() {});
|
||||
if (responseOne != null) {
|
||||
// String smsResponse = responseOne.getBody();
|
||||
if (!responseOne.getStatusCode().equals(HttpStatus.ACCEPTED)) {
|
||||
System.out.println(responseOne.getStatusCode().name());
|
||||
throw new ConnectionFailureException(SmsCampaignConstants.SMS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTriggeredMessages(Map<SmsCampaign, Collection<SmsMessage>> smsDataMap) {
|
||||
try {
|
||||
if (!smsDataMap.isEmpty()) {
|
||||
for (Entry<SmsCampaign, Collection<SmsMessage>> entry : smsDataMap.entrySet()) {
|
||||
Iterator<SmsMessage> smsMessageIterator = entry.getValue().iterator();
|
||||
Collection<SmsMessageApiQueueResourceData> apiQueueResourceDatas = new ArrayList<>();
|
||||
StringBuilder request = new StringBuilder();
|
||||
while (smsMessageIterator.hasNext()) {
|
||||
SmsMessage smsMessage = smsMessageIterator.next();
|
||||
SmsMessageApiQueueResourceData apiQueueResourceData = SmsMessageApiQueueResourceData.instance(smsMessage.getId(),
|
||||
null, null, null, smsMessage.getMobileNo(), smsMessage.getMessage(), entry.getKey().getProviderId());
|
||||
apiQueueResourceDatas.add(apiQueueResourceData);
|
||||
smsMessage.setStatusType(SmsMessageStatusType.WAITING_FOR_DELIVERY_REPORT.getValue());
|
||||
}
|
||||
this.smsMessageRepository.save(entry.getValue()) ;
|
||||
request.append(SmsMessageApiQueueResourceData.toJsonString(apiQueueResourceDatas));
|
||||
logger.info("Sending triggered SMS with request - " + request.toString());
|
||||
this.triggeredExecutorService.execute(new SmsTask(ThreadLocalContextUtil.getTenant(), apiQueueResourceDatas));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get SMS message delivery reports from the SMS gateway (or intermediate
|
||||
* gateway)
|
||||
**/
|
||||
@Override
|
||||
@Transactional
|
||||
@CronTarget(jobName = JobName.GET_DELIVERY_REPORTS_FROM_SMS_GATEWAY)
|
||||
public void getDeliveryReports() {
|
||||
int page = 0;
|
||||
int totalRecords = 0;
|
||||
Integer limit = 200;
|
||||
do {
|
||||
Page<Long> smsMessageInternalIds = this.smsReadPlatformService.retrieveAllWaitingForDeliveryReport(limit);
|
||||
// only proceed if there are sms message with status type enum 300
|
||||
try {
|
||||
|
||||
if (smsMessageInternalIds.getPageItems().size() > 0) {
|
||||
// make request
|
||||
Map<String, Object> hostConfig = this.smsConfigUtils.getMessageGateWayRequestURI("sms", new Gson().toJson(smsMessageInternalIds.getPageItems())) ;
|
||||
URI uri = (URI)hostConfig.get("uri") ;
|
||||
HttpEntity<?> entity = (HttpEntity<?>)hostConfig.get("entity") ;
|
||||
ResponseEntity<Collection<SmsMessageDeliveryReportData>> responseOne = restTemplate.exchange(uri, HttpMethod.POST, entity,
|
||||
new ParameterizedTypeReference<Collection<SmsMessageDeliveryReportData>>() {});
|
||||
|
||||
Collection<SmsMessageDeliveryReportData> smsMessageDeliveryReportDatas = responseOne.getBody();
|
||||
Iterator<SmsMessageDeliveryReportData> responseReportIterator = smsMessageDeliveryReportDatas.iterator();
|
||||
while (responseReportIterator.hasNext()) {
|
||||
SmsMessageDeliveryReportData smsMessageDeliveryReportData = responseReportIterator.next();
|
||||
Integer deliveryStatus = smsMessageDeliveryReportData.getDeliveryStatus();
|
||||
|
||||
if (!smsMessageDeliveryReportData.getHasError()
|
||||
&& (deliveryStatus != 100)) {
|
||||
SmsMessage smsMessage = this.smsMessageRepository.findOne(smsMessageDeliveryReportData.getId());
|
||||
Integer statusType = smsMessage.getStatusType();
|
||||
boolean statusChanged = false;
|
||||
|
||||
switch (deliveryStatus) {
|
||||
case 0:
|
||||
statusType = SmsMessageStatusType.INVALID.getValue();
|
||||
break;
|
||||
case 150:
|
||||
statusType = SmsMessageStatusType.WAITING_FOR_DELIVERY_REPORT.getValue();
|
||||
break;
|
||||
case 200:
|
||||
statusType = SmsMessageStatusType.SENT.getValue();
|
||||
break;
|
||||
case 300:
|
||||
statusType = SmsMessageStatusType.DELIVERED.getValue();
|
||||
break;
|
||||
|
||||
case 400:
|
||||
statusType = SmsMessageStatusType.FAILED.getValue();
|
||||
break;
|
||||
|
||||
default:
|
||||
statusType = smsMessage.getStatusType();
|
||||
break;
|
||||
}
|
||||
|
||||
statusChanged = !statusType.equals(smsMessage.getStatusType());
|
||||
|
||||
// update the status Type enum
|
||||
smsMessage.setStatusType(statusType);
|
||||
|
||||
// save the SmsMessage entity
|
||||
this.smsMessageRepository.save(smsMessage);
|
||||
|
||||
if (statusChanged) {
|
||||
logger.info("Status of SMS message id: " + smsMessage.getId() + " successfully changed to " + statusType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (smsMessageDeliveryReportDatas.size() > 0) {
|
||||
logger.info(smsMessageDeliveryReportDatas.size() + " "
|
||||
+ "delivery report(s) successfully received from the intermediate gateway - sms");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
page ++;
|
||||
totalRecords = smsMessageInternalIds.getTotalFilteredRecords();
|
||||
} while (page < totalRecords);
|
||||
}
|
||||
}
|
||||
+20
@@ -19,7 +19,11 @@
|
||||
package org.apache.fineract.infrastructure.sms.service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.service.Page;
|
||||
import org.apache.fineract.infrastructure.core.service.SearchParameters;
|
||||
import org.apache.fineract.infrastructure.sms.data.SmsData;
|
||||
|
||||
public interface SmsReadPlatformService {
|
||||
@@ -27,4 +31,20 @@ public interface SmsReadPlatformService {
|
||||
Collection<SmsData> retrieveAll();
|
||||
|
||||
SmsData retrieveOne(Long resourceId);
|
||||
|
||||
Collection<SmsData> retrieveAllPending(final Long campaignId, final Integer limit);
|
||||
|
||||
Collection<SmsData> retrieveAllSent(Integer limit);
|
||||
|
||||
Collection<SmsData> retrieveAllDelivered(Integer limit);
|
||||
|
||||
Collection<SmsData> retrieveAllFailed(Integer limit);
|
||||
|
||||
Page<SmsData> retrieveSmsByStatus(final Long campaignId, SearchParameters searchParameters, Integer status, Date dateFrom, Date dateTo);
|
||||
|
||||
List<Long> retrieveExternalIdsOfAllSent(Integer limit);
|
||||
|
||||
Page<Long> retrieveAllWaitingForDeliveryReport(Integer limit);
|
||||
|
||||
List<Long> retrieveAllPending(Integer limit);
|
||||
}
|
||||
|
||||
+142
-3
@@ -20,13 +20,22 @@ package org.apache.fineract.infrastructure.sms.service;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
|
||||
import org.apache.fineract.infrastructure.core.service.Page;
|
||||
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
|
||||
import org.apache.fineract.infrastructure.core.service.SearchParameters;
|
||||
import org.apache.fineract.infrastructure.sms.data.SmsData;
|
||||
import org.apache.fineract.infrastructure.sms.domain.SmsMessageEnumerations;
|
||||
import org.apache.fineract.infrastructure.sms.domain.SmsMessageStatusType;
|
||||
import org.apache.fineract.infrastructure.sms.exception.SmsNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
@@ -39,6 +48,7 @@ public class SmsReadPlatformServiceImpl implements SmsReadPlatformService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final SmsMapper smsRowMapper;
|
||||
private final PaginationHelper<SmsData> paginationHelper = new PaginationHelper<>();
|
||||
|
||||
@Autowired
|
||||
public SmsReadPlatformServiceImpl(final RoutingDataSource dataSource) {
|
||||
@@ -58,8 +68,11 @@ public class SmsReadPlatformServiceImpl implements SmsReadPlatformService {
|
||||
sql.append("smo.staff_id as staffId, ");
|
||||
sql.append("smo.status_enum as statusId, ");
|
||||
sql.append("smo.mobile_no as mobileNo, ");
|
||||
sql.append("smo.message as message ");
|
||||
sql.append("from sms_messages_outbound smo");
|
||||
sql.append("smo.message as message, ");
|
||||
sql.append("smc.provider_id as providerId, ");
|
||||
sql.append("smc.campaign_name as campaignName ");
|
||||
sql.append("from sms_messages_outbound smo ");
|
||||
sql.append("join sms_campaign smc on smc.id = smo.campaign_id ");
|
||||
|
||||
this.schema = sql.toString();
|
||||
}
|
||||
@@ -67,6 +80,10 @@ public class SmsReadPlatformServiceImpl implements SmsReadPlatformService {
|
||||
public String schema() {
|
||||
return this.schema;
|
||||
}
|
||||
|
||||
public String tableName() {
|
||||
return "sms_messages_outbound";
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
@@ -82,7 +99,11 @@ public class SmsReadPlatformServiceImpl implements SmsReadPlatformService {
|
||||
final Integer statusId = JdbcSupport.getInteger(rs, "statusId");
|
||||
final EnumOptionData status = SmsMessageEnumerations.status(statusId);
|
||||
|
||||
return SmsData.instance(id, groupId, clientId, staffId, status, mobileNo, message);
|
||||
final Long providerId = JdbcSupport.getLong(rs, "providerId");
|
||||
|
||||
final String campaignName = rs.getString("campaignName");
|
||||
|
||||
return SmsData.instance(id, groupId, clientId, staffId, status, mobileNo, message, providerId, campaignName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,4 +125,122 @@ public class SmsReadPlatformServiceImpl implements SmsReadPlatformService {
|
||||
throw new SmsNotFoundException(resourceId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SmsData> retrieveAllPending(final Long campaignId, final Integer limit) {
|
||||
final String sqlPlusLimit = (limit > 0) ? " limit 0, " + limit : "";
|
||||
String sql = "select " + this.smsRowMapper.schema() + " where smo.status_enum = " + SmsMessageStatusType.PENDING.getValue();
|
||||
if (campaignId != null) {
|
||||
sql += " and smo.campaign_id = " + campaignId;
|
||||
}
|
||||
|
||||
sql += sqlPlusLimit;
|
||||
|
||||
return this.jdbcTemplate.query(sql, this.smsRowMapper, new Object[] {});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SmsData> retrieveAllSent(final Integer limit) {
|
||||
final String sqlPlusLimit = (limit > 0) ? " limit 0, " + limit : "";
|
||||
final String sql = "select " + this.smsRowMapper.schema() + " where smo.status_enum IN (" + SmsMessageStatusType.WAITING_FOR_DELIVERY_REPORT.getValue()
|
||||
+ "," + SmsMessageStatusType.SENT.getValue() + ")" + sqlPlusLimit;
|
||||
|
||||
return this.jdbcTemplate.query(sql, this.smsRowMapper, new Object[] {});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> retrieveExternalIdsOfAllSent(final Integer limit) {
|
||||
final String sqlPlusLimit = (limit > 0) ? " limit 0, " + limit : "";
|
||||
final String sql = "select external_id from " + this.smsRowMapper.tableName() + " where status_enum = "
|
||||
+ SmsMessageStatusType.SENT.getValue() + sqlPlusLimit;
|
||||
|
||||
return this.jdbcTemplate.queryForList(sql, Long.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Long> retrieveAllWaitingForDeliveryReport(final Integer limit) {
|
||||
final String sqlPlusLimit = (limit > 0) ? " limit 0, " + limit : "";
|
||||
final String sql = "select id from " + this.smsRowMapper.tableName() + " where status_enum = "
|
||||
+ SmsMessageStatusType.WAITING_FOR_DELIVERY_REPORT.getValue() + sqlPlusLimit;
|
||||
final String sqlCountRows = "SELECT FOUND_ROWS()";
|
||||
return this.paginationHelper.fetchPage(jdbcTemplate, sql, sqlCountRows, Long.class);
|
||||
//(this.jdbcTemplate, sqlCountRows, new Object [] {}, Long.class); this.jdbcTemplate.queryForList(sql, Long.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> retrieveAllPending(final Integer limit) {
|
||||
final String sqlPlusLimit = (limit > 0) ? " limit 0, " + limit : "";
|
||||
final String sql = "select external_id from " + this.smsRowMapper.tableName() + " where status_enum = "
|
||||
+ SmsMessageStatusType.PENDING.getValue() + sqlPlusLimit;
|
||||
|
||||
return this.jdbcTemplate.queryForList(sql, Long.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SmsData> retrieveAllDelivered(final Integer limit) {
|
||||
final String sqlPlusLimit = (limit > 0) ? " limit 0, " + limit : "";
|
||||
final String sql = "select " + this.smsRowMapper.schema() + " where smo.status_enum = " + SmsMessageStatusType.DELIVERED.getValue()
|
||||
+ sqlPlusLimit;
|
||||
|
||||
return this.jdbcTemplate.query(sql, this.smsRowMapper, new Object[] {});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SmsData> retrieveAllFailed(final Integer limit) {
|
||||
final String sqlPlusLimit = (limit > 0) ? " limit 0, " + limit : "";
|
||||
final String sql = "select " + this.smsRowMapper.schema() + " where smo.status_enum = " + SmsMessageStatusType.FAILED.getValue()
|
||||
+ sqlPlusLimit;
|
||||
|
||||
return this.jdbcTemplate.query(sql, this.smsRowMapper, new Object[] {});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<SmsData> retrieveSmsByStatus(final Long campaignId, final SearchParameters searchParameters, final Integer status, final Date dateFrom, final Date dateTo) {
|
||||
final StringBuilder sqlBuilder = new StringBuilder(200);
|
||||
final Object[] objectArray = new Object[10];
|
||||
int arrayPos = 0;
|
||||
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
|
||||
sqlBuilder.append(this.smsRowMapper.schema());
|
||||
if (status != null) {
|
||||
sqlBuilder.append(" where smo.campaign_id = ? and smo.status_enum= ? ");
|
||||
objectArray[arrayPos] = campaignId;
|
||||
arrayPos = arrayPos + 1;
|
||||
objectArray[arrayPos] = status;
|
||||
arrayPos = arrayPos + 1;
|
||||
}
|
||||
String fromDateString = null;
|
||||
String toDateString = null;
|
||||
if (dateFrom != null && dateTo != null) {
|
||||
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
|
||||
fromDateString = df.format(dateFrom);
|
||||
toDateString = df.format(dateTo);
|
||||
sqlBuilder.append(" and smo.submittedon_date >= ? and smo.submittedon_date <= ? ");
|
||||
objectArray[arrayPos] = fromDateString;
|
||||
arrayPos = arrayPos + 1;
|
||||
|
||||
objectArray[arrayPos] = toDateString;
|
||||
arrayPos = arrayPos + 1;
|
||||
}
|
||||
|
||||
if (searchParameters.isOrderByRequested()) {
|
||||
sqlBuilder.append(" order by ").append(searchParameters.getOrderBy());
|
||||
|
||||
if (searchParameters.isSortOrderProvided()) {
|
||||
sqlBuilder.append(' ').append(searchParameters.getSortOrder());
|
||||
}
|
||||
} else {
|
||||
sqlBuilder.append(" order by smo.submittedon_date, smo.id");
|
||||
}
|
||||
|
||||
if (searchParameters.isLimited()) {
|
||||
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
|
||||
if (searchParameters.isOffset()) {
|
||||
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
|
||||
}
|
||||
}
|
||||
final String sqlCountRows = "SELECT FOUND_ROWS()";
|
||||
final Object[] finalObjectArray = Arrays.copyOf(objectArray, arrayPos);
|
||||
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), finalObjectArray, this.smsRowMapper);
|
||||
}
|
||||
|
||||
}
|
||||
+7
-1
@@ -46,6 +46,7 @@ import org.apache.fineract.infrastructure.codes.domain.CodeValue;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
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.documentmanagement.domain.Image;
|
||||
@@ -57,7 +58,6 @@ import org.apache.fineract.portfolio.group.domain.Group;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_client", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_no" }, name = "account_no_UNIQUE"), //
|
||||
@@ -1004,4 +1004,10 @@ public final class Client extends AbstractPersistableCustom<Long> {
|
||||
public void loadLazyCollections() {
|
||||
this.groups.size() ;
|
||||
}
|
||||
|
||||
public String getFirstname(){return this.firstname;}
|
||||
|
||||
public String getMiddlename(){return this.middlename;}
|
||||
|
||||
public String getLastname(){return this.lastname;}
|
||||
}
|
||||
+4
@@ -205,6 +205,10 @@ public class ClientTransaction extends AbstractPersistableCustom<Long> {
|
||||
return client.getId();
|
||||
}
|
||||
|
||||
public Client getClient() {
|
||||
return this.client ;
|
||||
}
|
||||
|
||||
public Money getAmount() {
|
||||
return Money.of(getCurrency(), this.amount);
|
||||
}
|
||||
|
||||
+52
-18
@@ -19,6 +19,7 @@
|
||||
package org.apache.fineract.portfolio.client.service;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -63,6 +64,9 @@ import org.apache.fineract.portfolio.client.exception.ClientHasNoStaffException;
|
||||
import org.apache.fineract.portfolio.client.exception.ClientMustBePendingToBeDeletedException;
|
||||
import org.apache.fineract.portfolio.client.exception.InvalidClientSavingProductException;
|
||||
import org.apache.fineract.portfolio.client.exception.InvalidClientStateTransitionException;
|
||||
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY;
|
||||
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS;
|
||||
import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.portfolio.group.domain.Group;
|
||||
import org.apache.fineract.portfolio.group.domain.GroupRepository;
|
||||
import org.apache.fineract.portfolio.group.exception.GroupMemberCountNotInPermissibleRangeException;
|
||||
@@ -113,13 +117,15 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
private final CommandProcessingService commandProcessingService;
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final ConfigurationReadPlatformService configurationReadPlatformService;
|
||||
private final AddressWritePlatformService addressWritePlatformService;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final ConfigurationReadPlatformService configurationReadPlatformService;
|
||||
private final AddressWritePlatformService addressWritePlatformService;
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
|
||||
@Autowired
|
||||
public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
final ClientRepositoryWrapper clientRepository, final ClientNonPersonRepositoryWrapper clientNonPersonRepository, final OfficeRepositoryWrapper officeRepositoryWrapper, final NoteRepository noteRepository,
|
||||
final ClientRepositoryWrapper clientRepository, final ClientNonPersonRepositoryWrapper clientNonPersonRepository,
|
||||
final OfficeRepositoryWrapper officeRepositoryWrapper, final NoteRepository noteRepository,
|
||||
final ClientDataValidator fromApiJsonDeserializer, final AccountNumberGenerator accountNumberGenerator,
|
||||
final GroupRepository groupRepository, final StaffRepositoryWrapper staffRepository,
|
||||
final CodeValueRepositoryWrapper codeValueRepository, final LoanRepositoryWrapper loanRepositoryWrapper,
|
||||
@@ -128,7 +134,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
final CommandProcessingService commandProcessingService, final ConfigurationDomainService configurationDomainService,
|
||||
final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, final FromJsonHelper fromApiJsonHelper,
|
||||
final ConfigurationReadPlatformService configurationReadPlatformService,
|
||||
final AddressWritePlatformService addressWritePlatformService) {
|
||||
final AddressWritePlatformService addressWritePlatformService, final BusinessEventNotifierService businessEventNotifierService) {
|
||||
this.context = context;
|
||||
this.clientRepository = clientRepository;
|
||||
this.clientNonPersonRepository = clientNonPersonRepository;
|
||||
@@ -147,8 +153,9 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
this.accountNumberFormatRepository = accountNumberFormatRepository;
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
this.configurationReadPlatformService = configurationReadPlatformService;
|
||||
this.addressWritePlatformService = addressWritePlatformService;
|
||||
this.configurationReadPlatformService = configurationReadPlatformService;
|
||||
this.addressWritePlatformService = addressWritePlatformService;
|
||||
this.businessEventNotifierService = businessEventNotifierService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -158,7 +165,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
|
||||
|
||||
if (client.isNotPending()) { throw new ClientMustBePendingToBeDeletedException(clientId); }
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.CLIENTS_DELETE,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
final List<Note> relatedNotes = this.noteRepository.findByClientId(clientId);
|
||||
this.noteRepository.deleteInBatch(relatedNotes);
|
||||
|
||||
@@ -167,7 +175,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
this.clientNonPersonRepository.delete(clientNonPerson);
|
||||
|
||||
this.clientRepository.delete(client);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.CLIENTS_DELETE,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withOfficeId(client.officeId()) //
|
||||
.withClientId(clientId) //
|
||||
@@ -275,6 +284,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
|
||||
final Client newClient = Client.createNew(currentUser, clientOffice, clientParentGroup, staff, savingsProductId, gender,
|
||||
clientType, clientClassification, legalFormValue, command);
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.CLIENTS_CREATE,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, newClient));
|
||||
boolean rollbackTransaction = false;
|
||||
if (newClient.isActive()) {
|
||||
validateParentGroupRulesBeforeClientActivation(newClient);
|
||||
@@ -306,7 +317,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
this.addressWritePlatformService.addNewClientAddress(newClient, command);
|
||||
}
|
||||
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.CLIENTS_CREATE,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, newClient));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withOfficeId(clientOffice.getId()) //
|
||||
@@ -523,7 +535,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
|
||||
final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId, true);
|
||||
validateParentGroupRulesBeforeClientActivation(client);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.CLIENTS_ACTIVATE,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
final LocalDate activationDate = command.localDateValueOfParameterNamed("activationDate");
|
||||
@@ -532,7 +545,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
client.activate(currentUser, fmt, activationDate);
|
||||
CommandProcessingResult result = openSavingsAccount(client, fmt);
|
||||
this.clientRepository.saveAndFlush(client);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.CLIENTS_ACTIVATE,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withOfficeId(client.officeId()) //
|
||||
@@ -609,7 +623,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
this.fromApiJsonDeserializer.validateForAssignStaff(command.json());
|
||||
|
||||
final Client clientForUpdate = this.clientRepository.findOneWithNotFoundDetection(clientId);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.CLIENTS_ASSIGN_STAFF,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, clientForUpdate));
|
||||
Staff staff = null;
|
||||
final Long staffId = command.longValueOfParameterNamed(ClientApiConstants.staffIdParamName);
|
||||
if (staffId != null) {
|
||||
@@ -625,7 +640,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
this.clientRepository.saveAndFlush(clientForUpdate);
|
||||
|
||||
actualChanges.put(ClientApiConstants.staffIdParamName, staffId);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.CLIENTS_ASSIGN_STAFF,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, clientForUpdate));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withOfficeId(clientForUpdate.officeId()) //
|
||||
@@ -644,6 +660,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
this.fromApiJsonDeserializer.validateClose(command);
|
||||
|
||||
final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.CLIENTS_CLOSE,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
final LocalDate closureDate = command.localDateValueOfParameterNamed(ClientApiConstants.closureDateParamName);
|
||||
final Long closureReasonId = command.longValueOfParameterNamed(ClientApiConstants.closureReasonIdParamName);
|
||||
|
||||
@@ -689,7 +707,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
|
||||
client.close(currentUser, closureReason, closureDate.toDate());
|
||||
this.clientRepository.saveAndFlush(client);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.CLIENTS_CLOSE,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withClientId(clientId) //
|
||||
@@ -763,6 +782,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
this.fromApiJsonDeserializer.validateRejection(command);
|
||||
|
||||
final Client client = this.clientRepository.findOneWithNotFoundDetection(entityId);
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.CLIENTS_REJECT,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
final LocalDate rejectionDate = command.localDateValueOfParameterNamed(ClientApiConstants.rejectionDateParamName);
|
||||
final Long rejectionReasonId = command.longValueOfParameterNamed(ClientApiConstants.rejectionReasonIdParamName);
|
||||
|
||||
@@ -780,7 +801,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
}
|
||||
client.reject(currentUser, rejectionReason, rejectionDate.toDate());
|
||||
this.clientRepository.saveAndFlush(client);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.CLIENTS_REJECT,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withClientId(entityId) //
|
||||
@@ -794,6 +816,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
this.fromApiJsonDeserializer.validateWithdrawn(command);
|
||||
|
||||
final Client client = this.clientRepository.findOneWithNotFoundDetection(entityId);
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.CLIENTS_WITHDRAW,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
final LocalDate withdrawalDate = command.localDateValueOfParameterNamed(ClientApiConstants.withdrawalDateParamName);
|
||||
final Long withdrawalReasonId = command.longValueOfParameterNamed(ClientApiConstants.withdrawalReasonIdParamName);
|
||||
|
||||
@@ -811,7 +835,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
}
|
||||
client.withdraw(currentUser, withdrawalReason, withdrawalDate.toDate());
|
||||
this.clientRepository.saveAndFlush(client);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.CLIENTS_WITHDRAW,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withClientId(entityId) //
|
||||
@@ -825,6 +850,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
this.fromApiJsonDeserializer.validateReactivate(command);
|
||||
|
||||
final Client client = this.clientRepository.findOneWithNotFoundDetection(entityId);
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.CLIENTS_REACTIVATE,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
final LocalDate reactivateDate = command.localDateValueOfParameterNamed(ClientApiConstants.reactivationDateParamName);
|
||||
|
||||
if (!client.isClosed()) {
|
||||
@@ -837,7 +864,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
}
|
||||
client.reActivate(currentUser, reactivateDate.toDate());
|
||||
this.clientRepository.saveAndFlush(client);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.CLIENTS_REACTIVATE,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withClientId(entityId) //
|
||||
@@ -899,4 +927,10 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
.withEntityId(entityId) //
|
||||
.build();
|
||||
}
|
||||
|
||||
private Map<BUSINESS_ENTITY, Object> constructEntityMap(final BUSINESS_ENTITY entityEvent, Object entity) {
|
||||
Map<BUSINESS_ENTITY, Object> map = new HashMap<>(1);
|
||||
map.put(entityEvent, entity);
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
+21
-10
@@ -24,15 +24,25 @@ import java.util.Set;
|
||||
public class BusinessEventNotificationConstants {
|
||||
|
||||
public static enum BUSINESS_EVENTS {
|
||||
LOAN_APPROVED("loan_approved"), LOAN_UNDO_APPROVAL("loan_undo_approval"), LOAN_UNDO_DISBURSAL("loan_undo_disbursal"), LOAN_UNDO_LASTDISBURSAL("loan_undo_lastdisbursal"),LOAN_UNDO_TRANSACTION(
|
||||
"loan_undo_transaction"), LOAN_ADJUST_TRANSACTION("loan_adjust_transaction"), LOAN_MAKE_REPAYMENT(
|
||||
"loan_repayment_transaction"), LOAN_WRITTEN_OFF("loan_writtenoff"), LOAN_UNDO_WRITTEN_OFF("loan_undo_writtenoff"), LOAN_DISBURSAL(
|
||||
"loan_disbursal"), LOAN_WAIVE_INTEREST("loan_waive_interest"), LOAN_CLOSE("loan_close"), LOAN_CLOSE_AS_RESCHEDULE(
|
||||
"loan_close_as_reschedule"), LOAN_ADD_CHARGE("loan_add_charge"), LOAN_UPDATE_CHARGE("loan_update_charge"), LOAN_WAIVE_CHARGE(
|
||||
"loan_waive_charge"), LOAN_DELETE_CHARGE("loan_delete_charge"), LOAN_CHARGE_PAYMENT("loan_charge_payment"), LOAN_INITIATE_TRANSFER(
|
||||
"loan_initiate_transfer"), LOAN_ACCEPT_TRANSFER("loan_accept_transfer"), LOAN_WITHDRAW_TRANSFER("loan_withdraw_transfer"), LOAN_REJECT_TRANSFER(
|
||||
"loan_reject_transfer"), LOAN_REASSIGN_OFFICER("loan_reassign_officer"), LOAN_REMOVE_OFFICER("loan_remove_officer"), LOAN_APPLY_OVERDUE_CHARGE(
|
||||
"loan_apply_overdue_charge"), LOAN_INTEREST_RECALCULATION("loan_interest_recalculation"), LOAN_REFUND("loan_refund"), LOAN_FORECLOSURE("loan_foreclosure");
|
||||
LOAN_APPROVED("loan_approved"), LOAN_REJECTED("loan_reject"), LOAN_UNDO_APPROVAL("loan_undo_approval"), LOAN_UNDO_DISBURSAL("loan_undo_disbursal"), LOAN_UNDO_LASTDISBURSAL(
|
||||
"loan_undo_lastdisbursal"), LOAN_UNDO_TRANSACTION("loan_undo_transaction"), LOAN_ADJUST_TRANSACTION(
|
||||
"loan_adjust_transaction"), LOAN_MAKE_REPAYMENT("loan_repayment_transaction"), LOAN_WRITTEN_OFF("loan_writtenoff"), LOAN_UNDO_WRITTEN_OFF(
|
||||
"loan_undo_writtenoff"), LOAN_DISBURSAL("loan_disbursal"), LOAN_WAIVE_INTEREST("loan_waive_interest"), LOAN_CLOSE(
|
||||
"loan_close"), LOAN_CLOSE_AS_RESCHEDULE("loan_close_as_reschedule"), LOAN_ADD_CHARGE("loan_add_charge"), LOAN_UPDATE_CHARGE(
|
||||
"loan_update_charge"), LOAN_WAIVE_CHARGE("loan_waive_charge"), LOAN_DELETE_CHARGE("loan_delete_charge"), LOAN_CHARGE_PAYMENT(
|
||||
"loan_charge_payment"), LOAN_INITIATE_TRANSFER("loan_initiate_transfer"), LOAN_ACCEPT_TRANSFER("loan_accept_transfer"), LOAN_WITHDRAW_TRANSFER(
|
||||
"loan_withdraw_transfer"), LOAN_REJECT_TRANSFER("loan_reject_transfer"), LOAN_REASSIGN_OFFICER("loan_reassign_officer"), LOAN_REMOVE_OFFICER(
|
||||
"loan_remove_officer"), LOAN_APPLY_OVERDUE_CHARGE("loan_apply_overdue_charge"), LOAN_INTEREST_RECALCULATION(
|
||||
"loan_interest_recalculation"), LOAN_REFUND("loan_refund"), LOAN_FORECLOSURE("loan_foreclosure"), SAVINGS_ACTIVATE(
|
||||
"savings_activated"), SAVINGS_ADJUST_TRANSACTION("savings_adjust_transaction"), SAVINGS_APPLY_ANNUAL_FEE(
|
||||
"savings_apply_annual_fee"), SAVINGS_CALCULATE_INTEREST("savings_calculate_interest"), SAVINGS_CLOSE("savings_close"), SAVINGS_POST_INTEREST(
|
||||
"savings_post_interest"), SAVINGS_REJECT("savings_reject"), SAVINGS_DEPOSIT("savings_deposit"), SAVINGS_WITHDRAWAL(
|
||||
"savings_withdrawal"), SAVINGS_UNDO("savings_undo"), SAVINGS_ADD_CHARGE("savings_add_charge"), SAVINGS_WAIVE_CHARGE(
|
||||
"savings_waive_charge"), SAVINGS_PAY_CHARGE("savings_pay_charge"), CLIENTS_ACCEPT_TRANSFER("clients_accept_transfer"), CLIENTS_ACTIVATE(
|
||||
"clients_activate"), CLIENTS_ASSIGN_STAFF("clients_assign_staff"), CLIENTS_CLOSE("clients_close"), CLIENTS_CREATE(
|
||||
"clients_create"), CLIENTS_DELETE("clients_delete"), CLIENTS_PROPOSE_TRANSFER("clients_propose_transfer"), CLIENTS_REACTIVATE(
|
||||
"clients_reactivate"), CLIENTS_REJECT("clients_reject"), CLIENTS_REJECT_TRANSFER("clients_reject_transfer"), CLIENTS_WITHDRAW(
|
||||
"clients_withdraw"), CLIENTS_WITHDRAW_TRANSFER("clients_withdraw_transfer");
|
||||
|
||||
private final String value;
|
||||
|
||||
@@ -58,7 +68,7 @@ public class BusinessEventNotificationConstants {
|
||||
|
||||
public static enum BUSINESS_ENTITY {
|
||||
LOAN("loan"), LOAN_TRANSACTION("loan_transaction"), LOAN_CHARGE("loan_charge"), LOAN_ADJUSTED_TRANSACTION(
|
||||
"loan_adjusted_transaction");
|
||||
"loan_adjusted_transaction"), SAVING("saving"), CLIENT("client"), SAVINGS_TRANSACTION("Savings Transaction");
|
||||
|
||||
private final String value;
|
||||
|
||||
@@ -70,4 +80,5 @@ public class BusinessEventNotificationConstants {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-4
@@ -358,7 +358,7 @@ public class LoansApiResource {
|
||||
public String retrieveLoan(@PathParam("loanId") final Long loanId,
|
||||
@DefaultValue("false") @QueryParam("staffInSelectedOfficeOnly") final boolean staffInSelectedOfficeOnly,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
long start = System.currentTimeMillis() ;
|
||||
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
|
||||
|
||||
LoanAccountData loanBasicDetails = this.loanReadPlatformService.retrieveOne(loanId);
|
||||
@@ -392,9 +392,7 @@ public class LoansApiResource {
|
||||
if(calendarData != null)
|
||||
loanBasicDetails = LoanAccountData.withLoanCalendarData(loanBasicDetails, calendarData);
|
||||
}
|
||||
|
||||
Collection<InterestRatePeriodData> interestRatesPeriods = this.loanReadPlatformService.retrieveLoanInterestRatePeriodData(loanBasicDetails);
|
||||
|
||||
Collection<LoanTransactionData> loanRepayments = null;
|
||||
LoanScheduleData repaymentSchedule = null;
|
||||
Collection<LoanChargeData> charges = null;
|
||||
@@ -597,7 +595,13 @@ public class LoansApiResource {
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters(),
|
||||
mandatoryResponseParameters);
|
||||
return this.toApiJsonSerializer.serialize(settings, loanAccount, this.LOAN_DATA_PARAMETERS);
|
||||
long end = System.currentTimeMillis() ;
|
||||
System.out.println("LoansApiResource.retrieveLoan() Time took: "+(end-start));
|
||||
start = System.currentTimeMillis() ;
|
||||
String toReturn = this.toApiJsonSerializer.serialize(settings, loanAccount, this.LOAN_DATA_PARAMETERS);
|
||||
end = System.currentTimeMillis() ;
|
||||
System.out.println("LoansApiResource.retrieveLoan() Time took to Serialize: "+(end-start));
|
||||
return toReturn ;
|
||||
}
|
||||
|
||||
@GET
|
||||
|
||||
+5
-1
@@ -6389,7 +6389,6 @@ public class Loan extends AbstractPersistableCustom<Long> {
|
||||
public Collection<LoanCharge> getLoanCharges() {
|
||||
return this.charges;
|
||||
}
|
||||
|
||||
public void initializeLazyCollections() {
|
||||
this.charges.size() ;
|
||||
this.trancheCharges.size() ;
|
||||
@@ -6412,4 +6411,9 @@ public class Loan extends AbstractPersistableCustom<Long> {
|
||||
public void initializeRepaymentSchedule() {
|
||||
this.repaymentScheduleInstallments.size() ;
|
||||
}
|
||||
public boolean hasInvalidLoanType() {
|
||||
return AccountType.fromInt(this.loanType).isInvalid();
|
||||
}
|
||||
|
||||
public boolean isIndividualLoan(){return AccountType.fromInt(this.loanType).isIndividualAccount();}
|
||||
}
|
||||
|
||||
+8
@@ -778,6 +778,14 @@ public class LoanTransaction extends AbstractPersistableCustom<Long> {
|
||||
return isAccrual();
|
||||
}
|
||||
|
||||
public BigDecimal getOutstandingLoanBalance() {
|
||||
return outstandingLoanBalance;
|
||||
}
|
||||
|
||||
public PaymentDetail getPaymentDetail() {
|
||||
return this.paymentDetail;
|
||||
}
|
||||
|
||||
public boolean isPaymentTransaction() {
|
||||
return this.isNotReversed()
|
||||
&& !(this.isDisbursement() || this.isAccrual() || this.isRepaymentAtDisbursement() || this.isNonMonetaryTransaction() || this
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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.portfolio.loanaccount.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
/**
|
||||
* {@link AbstractPlatformDomainRuleException} thrown an action to transition a
|
||||
* loan from one state to another violates a domain rule.
|
||||
*/
|
||||
public class InvalidLoanTypeException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public InvalidLoanTypeException(final String defaultUserMessage, final Object... defaultUserMessageArgs) {
|
||||
super("error.msg.loan.type.invalid", defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1233,7 +1233,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
}
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.LOAN_REJECTED, constructEntityMap(BUSINESS_ENTITY.LOAN, loan));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(loan.getId()) //
|
||||
|
||||
-1
@@ -392,7 +392,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
String sql = "select " + mapper.schema() + " where l.id =?";
|
||||
LoanTransactionData loanTransactionData = this.jdbcTemplate.queryForObject(sql, mapper, LoanTransactionType.REPAYMENT.getValue(),
|
||||
loanId, loanId);
|
||||
|
||||
final Collection<PaymentTypeData> paymentOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
|
||||
return LoanTransactionData.templateOnTop(loanTransactionData, paymentOptions);
|
||||
}
|
||||
|
||||
+1
@@ -115,4 +115,5 @@ public final class PaymentDetail extends AbstractPersistableCustom<Long> {
|
||||
return this.paymentType;
|
||||
}
|
||||
|
||||
public String getReceiptNumber() { return this.receiptNumber; }
|
||||
}
|
||||
+22
-6
@@ -25,6 +25,9 @@ import org.apache.fineract.infrastructure.security.service.PlatformSecurityConte
|
||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY;
|
||||
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS;
|
||||
import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.apache.fineract.portfolio.savings.SavingsAccountTransactionType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsTransactionBooleanValues;
|
||||
@@ -40,6 +43,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -55,6 +59,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
private final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository;
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountDomainServiceJpa(final SavingsAccountRepositoryWrapper savingsAccountRepository,
|
||||
@@ -62,7 +67,8 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper,
|
||||
final JournalEntryWritePlatformService journalEntryWritePlatformService,
|
||||
final ConfigurationDomainService configurationDomainService, final PlatformSecurityContext context,
|
||||
final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository) {
|
||||
final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository,
|
||||
final BusinessEventNotifierService businessEventNotifierService) {
|
||||
this.savingsAccountRepository = savingsAccountRepository;
|
||||
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
|
||||
this.applicationCurrencyRepositoryWrapper = applicationCurrencyRepositoryWrapper;
|
||||
@@ -70,6 +76,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
this.context = context;
|
||||
this.depositAccountOnHoldTransactionRepository = depositAccountOnHoldTransactionRepository;
|
||||
this.businessEventNotifierService = businessEventNotifierService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -82,9 +89,10 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
|
||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
|
||||
|
||||
if (transactionBooleanValues.isRegularTransaction() && !account.allowWithdrawal()) { throw new DepositAccountTransactionNotAllowedException(
|
||||
account.getId(), "withdraw", account.depositAccountType()); }
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.SAVINGS_WITHDRAWAL,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final boolean interestPostAsOn = false;
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
@@ -92,7 +100,6 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
|
||||
paymentDetail, new Date(), user);
|
||||
final SavingsAccountTransaction withdrawal = account.withdraw(transactionDTO, transactionBooleanValues.isApplyWithdrawFee());
|
||||
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
@@ -114,7 +121,8 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
this.savingsAccountRepository.save(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, transactionBooleanValues.isAccountTransfer());
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.SAVINGS_WITHDRAWAL,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
return withdrawal;
|
||||
}
|
||||
|
||||
@@ -147,7 +155,8 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
|
||||
if (isRegularTransaction && !account.allowDeposit()) { throw new DepositAccountTransactionNotAllowedException(account.getId(),
|
||||
"deposit", account.depositAccountType()); }
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.SAVINGS_DEPOSIT,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
boolean isInterestTransfer = false;
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
@@ -172,7 +181,8 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
this.savingsAccountRepository.save(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.SAVINGS_DEPOSIT,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
return deposit;
|
||||
}
|
||||
|
||||
@@ -218,4 +228,10 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
final boolean isAccountTransfer = false;
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
|
||||
}
|
||||
|
||||
private Map<BUSINESS_ENTITY, Object> constructEntityMap(final BUSINESS_ENTITY entityEvent, Object entity) {
|
||||
Map<BUSINESS_ENTITY, Object> map = new HashMap<>(1);
|
||||
map.put(entityEvent, entity);
|
||||
return map;
|
||||
}
|
||||
}
|
||||
+5
-3
@@ -729,16 +729,15 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom<L
|
||||
public void updateAmount(final Money amount) {
|
||||
this.amount = amount.getAmount();
|
||||
}
|
||||
|
||||
|
||||
public Integer getTypeOf() {
|
||||
return this.typeOf;
|
||||
}
|
||||
|
||||
|
||||
public SavingsAccount getSavingsAccount() {
|
||||
return this.savingsAccount;
|
||||
}
|
||||
|
||||
|
||||
public void setSavingsAccount(SavingsAccount savingsAccount) {
|
||||
this.savingsAccount = savingsAccount;
|
||||
}
|
||||
@@ -747,4 +746,7 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom<L
|
||||
return this.dateOf;
|
||||
}
|
||||
|
||||
public PaymentDetail getPaymentDetail() {
|
||||
return this.paymentDetail ;
|
||||
}
|
||||
}
|
||||
+62
-13
@@ -39,8 +39,6 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.fineract.accounting.journalentry.exception.JournalEntryInvalidException;
|
||||
import org.apache.fineract.accounting.journalentry.exception.JournalEntryInvalidException.GL_JOURNAL_ENTRY_INVALID_REASON;
|
||||
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
@@ -73,6 +71,9 @@ import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.client.exception.ClientNotActiveException;
|
||||
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY;
|
||||
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS;
|
||||
import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.portfolio.group.domain.Group;
|
||||
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
|
||||
import org.apache.fineract.portfolio.note.domain.Note;
|
||||
@@ -98,13 +99,13 @@ import org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRepository;
|
||||
import org.apache.fineract.portfolio.savings.exception.PostInterestAsOnDateException;
|
||||
import org.apache.fineract.portfolio.savings.exception.PostInterestAsOnDateException.PostInterestAsOnException_TYPE;
|
||||
import org.apache.fineract.portfolio.savings.exception.PostInterestClosingDateException;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsAccountClosingNotAllowedException;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsAccountTransactionNotFoundException;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsOfficerAssignmentException;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsOfficerUnassignmentException;
|
||||
import org.apache.fineract.portfolio.savings.exception.TransactionUpdateNotAllowedException;
|
||||
import org.apache.fineract.portfolio.savings.exception.PostInterestAsOnDateException.PostInterestAsOnException_TYPE;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper;
|
||||
import org.joda.time.LocalDate;
|
||||
@@ -141,6 +142,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
private final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository;
|
||||
private final AppUserRepositoryWrapper appuserRepository;
|
||||
private final StandingInstructionRepository standingInstructionRepository;
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
@@ -161,7 +163,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final StaffRepositoryWrapper staffRepository, final ConfigurationDomainService configurationDomainService,
|
||||
final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository,
|
||||
final AppUserRepositoryWrapper appuserRepository,
|
||||
final StandingInstructionRepository standingInstructionRepository) {
|
||||
final StandingInstructionRepository standingInstructionRepository,
|
||||
final BusinessEventNotifierService businessEventNotifierService) {
|
||||
this.context = context;
|
||||
this.savingAccountRepositoryWrapper = savingAccountRepositoryWrapper;
|
||||
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
|
||||
@@ -185,6 +188,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
this.depositAccountOnHoldTransactionRepository = depositAccountOnHoldTransactionRepository;
|
||||
this.appuserRepository = appuserRepository;
|
||||
this.standingInstructionRepository = standingInstructionRepository;
|
||||
this.businessEventNotifierService = businessEventNotifierService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -197,7 +201,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
checkClientOrGroupActive(account);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.SAVINGS_ACTIVATE,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
@@ -211,6 +216,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
}
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.SAVINGS_ACTIVATE,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsId) //
|
||||
@@ -272,6 +279,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
boolean isRegularTransaction = true;
|
||||
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(account, fmt, transactionDate,
|
||||
transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction);
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.SAVINGS_DEPOSIT,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVINGS_TRANSACTION, deposit));
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(deposit.getId()) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
@@ -315,6 +325,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(account, fmt, transactionDate,
|
||||
transactionAmount, paymentDetail, transactionBooleanValues);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.SAVINGS_WITHDRAWAL,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVINGS_TRANSACTION, withdrawal));
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(withdrawal.getId()) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
@@ -333,11 +346,14 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection(
|
||||
savingsAccountChargeId, accountId);
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.SAVINGS_APPLY_ANNUAL_FEE,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, savingsAccountCharge));
|
||||
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MM yyyy");
|
||||
|
||||
this.payCharge(savingsAccountCharge, savingsAccountCharge.getDueLocalDate(), savingsAccountCharge.amount(), fmt, user);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.SAVINGS_APPLY_ANNUAL_FEE,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, savingsAccountCharge));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsAccountCharge.getId()) //
|
||||
.withOfficeId(savingsAccountCharge.savingsAccount().officeId()) //
|
||||
@@ -357,7 +373,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
checkClientOrGroupActive(account);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.SAVINGS_CALCULATE_INTEREST,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
final MathContext mc = new MathContext(15, MoneyHelper.getRoundingMode());
|
||||
boolean isInterestTransfer = false;
|
||||
@@ -366,6 +383,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
this.savingAccountRepositoryWrapper.save(account);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.SAVINGS_CALCULATE_INTEREST,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
@@ -416,7 +436,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
|
||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.SAVINGS_POST_INTEREST,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
if (account.getNominalAnnualInterestRate().compareTo(BigDecimal.ZERO) > 0
|
||||
|| (account.allowOverdraft() && account.getNominalAnnualInterestRateOverdraft().compareTo(BigDecimal.ZERO) > 0)) {
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
@@ -442,6 +463,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.SAVINGS_POST_INTEREST,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,6 +477,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.SAVINGS_UNDO,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
@@ -506,7 +531,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
account.activateAccountBasedOnBalance();
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.SAVINGS_UNDO,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
@@ -541,6 +567,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.SAVINGS_ADJUST_TRANSACTION,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
if (account.isNotActive()) {
|
||||
throwValidationForActiveStatus(SavingsApiConstants.adjustTransactionAction);
|
||||
}
|
||||
@@ -595,6 +623,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
account.activateAccountBasedOnBalance();
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.SAVINGS_ADJUST_TRANSACTION,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(newtransactionId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
@@ -633,7 +663,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
this.savingsAccountTransactionDataValidator.validateClosing(command);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.SAVINGS_CLOSE,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
final boolean isLinkedWithAnyActiveLoan = this.accountAssociationsReadPlatformService.isLinkedWithAnyActiveAccount(savingsId);
|
||||
|
||||
if (isLinkedWithAnyActiveLoan) {
|
||||
@@ -700,7 +731,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
// disable all standing orders linked to the savings account
|
||||
this.disableStandingInstructionsLinkedToClosedSavings(account);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.SAVINGS_CLOSE,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
@@ -829,6 +861,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsAccountId);
|
||||
checkClientOrGroupActive(savingsAccount);
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.SAVINGS_ADD_CHARGE,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, savingsAccount));
|
||||
|
||||
final Locale locale = command.extractLocale();
|
||||
final String format = command.dateFormat();
|
||||
@@ -867,7 +901,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
savingsAccount.addCharge(fmt, savingsAccountCharge, chargeDefinition);
|
||||
this.savingsAccountChargeRepository.save(savingsAccountCharge);
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(savingsAccount);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.SAVINGS_ADD_CHARGE,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, savingsAccount));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsAccountCharge.getId()) //
|
||||
.withOfficeId(savingsAccount.officeId()) //
|
||||
@@ -946,6 +981,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
// Get Savings account from savings charge
|
||||
final SavingsAccount account = savingsAccountCharge.savingsAccount();
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.SAVINGS_WAIVE_CHARGE,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
this.savingAccountAssembler.assignSavingAccountHelpers(account);
|
||||
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
@@ -977,7 +1014,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.SAVINGS_WAIVE_CHARGE,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, account));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsAccountChargeId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
@@ -1023,6 +1061,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection(
|
||||
savingsAccountChargeId, savingsAccountId);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.SAVINGS_PAY_CHARGE,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, savingsAccountCharge));
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
@@ -1044,6 +1085,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
}
|
||||
|
||||
this.payCharge(savingsAccountCharge, transactionDate, amountPaid, fmt, user);
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.SAVINGS_PAY_CHARGE,
|
||||
constructEntityMap(BUSINESS_ENTITY.SAVING, savingsAccountCharge));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsAccountCharge.getId()) //
|
||||
.withOfficeId(savingsAccountCharge.savingsAccount().officeId()) //
|
||||
@@ -1352,4 +1395,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<BUSINESS_ENTITY, Object> constructEntityMap(final BUSINESS_ENTITY entityEvent, Object entity) {
|
||||
Map<BUSINESS_ENTITY, Object> map = new HashMap<>(1);
|
||||
map.put(entityEvent, entity);
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
+17
-3
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.savings.service;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@@ -53,6 +54,9 @@ import org.apache.fineract.portfolio.client.domain.AccountNumberGenerator;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.client.exception.ClientNotActiveException;
|
||||
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY;
|
||||
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS;
|
||||
import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.portfolio.group.domain.Group;
|
||||
import org.apache.fineract.portfolio.group.domain.GroupRepository;
|
||||
import org.apache.fineract.portfolio.group.exception.CenterNotActiveException;
|
||||
@@ -101,7 +105,8 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
private final SavingsAccountDomainService savingsAccountDomainService;
|
||||
private final SavingsAccountWritePlatformService savingsAccountWritePlatformService;
|
||||
private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository;
|
||||
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
|
||||
@Autowired
|
||||
public SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
final SavingsAccountRepositoryWrapper savingAccountRepository, final SavingsAccountAssembler savingAccountAssembler,
|
||||
@@ -113,7 +118,8 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
final SavingsAccountChargeAssembler savingsAccountChargeAssembler, final CommandProcessingService commandProcessingService,
|
||||
final SavingsAccountDomainService savingsAccountDomainService,
|
||||
final SavingsAccountWritePlatformService savingsAccountWritePlatformService,
|
||||
final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository) {
|
||||
final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository,
|
||||
final BusinessEventNotifierService businessEventNotifierService) {
|
||||
this.context = context;
|
||||
this.savingAccountRepository = savingAccountRepository;
|
||||
this.savingAccountAssembler = savingAccountAssembler;
|
||||
@@ -130,6 +136,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
this.savingsAccountDomainService = savingsAccountDomainService;
|
||||
this.accountNumberFormatRepository = accountNumberFormatRepository;
|
||||
this.savingsAccountWritePlatformService = savingsAccountWritePlatformService;
|
||||
this.businessEventNotifierService = businessEventNotifierService ;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -415,7 +422,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
}
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.SAVINGS_REJECT, constructEntityMap(BUSINESS_ENTITY.SAVING, savingsAccount));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(savingsId) //
|
||||
@@ -506,4 +513,11 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
.setRollbackTransaction(rollbackTransaction)//
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
private Map<BUSINESS_ENTITY, Object> constructEntityMap(final BUSINESS_ENTITY entityEvent, Object entity) {
|
||||
Map<BUSINESS_ENTITY, Object> map = new HashMap<>(1);
|
||||
map.put(entityEvent, entity);
|
||||
return map;
|
||||
}
|
||||
}
|
||||
+32
-5
@@ -20,7 +20,9 @@ package org.apache.fineract.portfolio.transfer.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
@@ -40,6 +42,9 @@ import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.client.domain.ClientStatus;
|
||||
import org.apache.fineract.portfolio.client.exception.ClientHasBeenClosedException;
|
||||
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY;
|
||||
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS;
|
||||
import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.portfolio.group.domain.Group;
|
||||
import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.group.exception.ClientNotInGroupException;
|
||||
@@ -79,6 +84,7 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
|
||||
private final TransfersDataValidator transfersDataValidator;
|
||||
private final NoteWritePlatformService noteWritePlatformService;
|
||||
private final StaffRepositoryWrapper staffRepositoryWrapper;
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
|
||||
@Autowired
|
||||
public TransferWritePlatformServiceJpaRepositoryImpl(final ClientRepositoryWrapper clientRepositoryWrapper,
|
||||
@@ -87,7 +93,8 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
|
||||
final LoanRepositoryWrapper loanRepositoryWrapper, final TransfersDataValidator transfersDataValidator,
|
||||
final NoteWritePlatformService noteWritePlatformService, final StaffRepositoryWrapper staffRepositoryWrapper,
|
||||
final SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper,
|
||||
final SavingsAccountWritePlatformService savingsAccountWritePlatformService) {
|
||||
final SavingsAccountWritePlatformService savingsAccountWritePlatformService,
|
||||
final BusinessEventNotifierService businessEventNotifierService) {
|
||||
this.clientRepositoryWrapper = clientRepositoryWrapper;
|
||||
this.officeRepository = officeRepository;
|
||||
this.calendarInstanceRepository = calendarInstanceRepository;
|
||||
@@ -99,6 +106,7 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
|
||||
this.staffRepositoryWrapper = staffRepositoryWrapper;
|
||||
this.savingsAccountRepositoryWrapper = savingsAccountRepositoryWrapper;
|
||||
this.savingsAccountWritePlatformService = savingsAccountWritePlatformService;
|
||||
this.businessEventNotifierService = businessEventNotifierService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -293,9 +301,12 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
|
||||
final Long destinationOfficeId = jsonCommand.longValueOfParameterNamed(TransferApiConstants.destinationOfficeIdParamName);
|
||||
final Office office = this.officeRepository.findOneWithNotFoundDetection(destinationOfficeId);
|
||||
final Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId);
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.CLIENTS_PROPOSE_TRANSFER,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
handleClientTransferLifecycleEvent(client, office, TransferEventType.PROPOSAL, jsonCommand);
|
||||
this.clientRepositoryWrapper.save(client);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.CLIENTS_PROPOSE_TRANSFER,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withClientId(clientId) //
|
||||
.withEntityId(clientId) //
|
||||
@@ -321,9 +332,12 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
|
||||
this.transfersDataValidator.validateForAcceptClientTransfer(jsonCommand.json());
|
||||
final Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId, true);
|
||||
validateClientAwaitingTransferAcceptance(client);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.CLIENTS_ACCEPT_TRANSFER,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
handleClientTransferLifecycleEvent(client, client.getTransferToOffice(), TransferEventType.ACCEPTANCE, jsonCommand);
|
||||
this.clientRepositoryWrapper.save(client);
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.CLIENTS_ACCEPT_TRANSFER,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withClientId(clientId) //
|
||||
@@ -337,11 +351,13 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
|
||||
// validation
|
||||
this.transfersDataValidator.validateForWithdrawClientTransfer(jsonCommand.json());
|
||||
final Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId);
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.CLIENTS_WITHDRAW_TRANSFER,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
validateClientAwaitingTransferAcceptanceOnHold(client);
|
||||
|
||||
handleClientTransferLifecycleEvent(client, client.getOffice(), TransferEventType.WITHDRAWAL, jsonCommand);
|
||||
this.clientRepositoryWrapper.save(client);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.CLIENTS_WITHDRAW_TRANSFER,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withClientId(clientId) //
|
||||
.withEntityId(clientId) //
|
||||
@@ -354,9 +370,14 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
|
||||
// validation
|
||||
this.transfersDataValidator.validateForRejectClientTransfer(jsonCommand.json());
|
||||
final Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId);
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.CLIENTS_REJECT_TRANSFER,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
handleClientTransferLifecycleEvent(client, client.getOffice(), TransferEventType.REJECTION, jsonCommand);
|
||||
this.clientRepositoryWrapper.save(client);
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.CLIENTS_REJECT_TRANSFER,
|
||||
constructEntityMap(BUSINESS_ENTITY.CLIENT, client));
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withClientId(clientId) //
|
||||
.withEntityId(clientId) //
|
||||
@@ -503,6 +524,12 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
|
||||
if (!client.isTransferInProgressOrOnHold()) { throw new ClientNotAwaitingTransferApprovalOrOnHoldException(client.getId()); }
|
||||
}
|
||||
|
||||
private Map<BUSINESS_ENTITY, Object> constructEntityMap(final BUSINESS_ENTITY entityEvent, Object entity) {
|
||||
Map<BUSINESS_ENTITY, Object> map = new HashMap<>(1);
|
||||
map.put(entityEvent, entity);
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* private void validateGroupAwaitingTransferAcceptanceOnHold(final Group
|
||||
* group) { if (!group.isTransferInProgressOrOnHold()) { throw new
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
<jpa:repositories base-package="org.apache.fineract.mix.domain" />
|
||||
<jpa:repositories base-package="org.apache.fineract.scheduledjobs.domain" />
|
||||
<jpa:repositories base-package="org.apache.fineract.template.domain" />
|
||||
<jpa:repositories base-package="org.apache.fineract.infrastructure.campaigns.sms.domain" />
|
||||
|
||||
<import resource="infrastructure.xml" />
|
||||
|
||||
|
||||
@@ -0,0 +1,277 @@
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
|
||||
CREATE TABLE `sms_campaign` (
|
||||
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
`campaign_name` VARCHAR(100) NOT NULL,
|
||||
`campaign_type` INT(11) NOT NULL,
|
||||
`campaign_trigger_type` INT(11) NOT NULL,
|
||||
`report_id` INT(11) NOT NULL,
|
||||
`provider_id` BIGINT(20) NOT NULL,
|
||||
`param_value` TEXT NULL,
|
||||
`status_enum` INT(11) NOT NULL,
|
||||
`message` TEXT NOT NULL,
|
||||
`submittedon_date` DATE NULL DEFAULT NULL,
|
||||
`submittedon_userid` BIGINT(20) NULL DEFAULT NULL,
|
||||
`approvedon_date` DATE NULL DEFAULT NULL,
|
||||
`approvedon_userid` BIGINT(20) NULL DEFAULT NULL,
|
||||
`closedon_date` DATE NULL DEFAULT NULL,
|
||||
`closedon_userid` BIGINT(20) NULL DEFAULT NULL,
|
||||
`recurrence` VARCHAR(100) NULL DEFAULT NULL,
|
||||
`next_trigger_date` DATETIME NULL DEFAULT NULL,
|
||||
`last_trigger_date` DATETIME NULL DEFAULT NULL,
|
||||
`recurrence_start_date` DATETIME NULL DEFAULT NULL,
|
||||
`is_visible` TINYINT(1) NULL DEFAULT '1',
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `report_id` (`report_id`),
|
||||
CONSTRAINT `sms_campaign_ibfk_1` FOREIGN KEY (`report_id`) REFERENCES `stretchy_report` (`id`)
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE `sms_messages_outbound`
|
||||
ADD COLUMN `campaign_id` BIGINT(20) NOT NULL,
|
||||
ADD COLUMN `external_id` BIGINT(20) NULL DEFAULT NULL,
|
||||
ADD COLUMN `submittedon_date` DATE NULL DEFAULT NULL,
|
||||
ADD COLUMN `delivered_on_date` DATETIME NULL DEFAULT NULL,
|
||||
ADD INDEX `FKCAMPAIGN00000001` (`campaign_id`),
|
||||
ADD CONSTRAINT `FKCAMPAIGN00000001` FOREIGN KEY (`campaign_id`) REFERENCES `sms_campaign` (`id`);
|
||||
|
||||
|
||||
INSERT INTO `job` (`name`, `display_name`, `cron_expression`, `create_time`, `task_priority`, `group_name`, `previous_run_start_time`, `next_run_time`, `job_key`, `initializing_errorlog`, `is_active`, `currently_running`, `updates_allowed`, `scheduler_group`, `is_misfired`) VALUES
|
||||
('Update Sms Outbound with campaign message', 'Update Sms Outbound with campaign message', '0 0 0 1/1 * ? *', NOW(), 3, NULL, NULL, NULL, 'Update Sms Outbound with campaign message1 _ DEFAULT', NULL, 0, 0, 1, 1, 0),
|
||||
('Send messages to SMS gateway', 'Send messages to SMS gateway', '0 0 0 1/1 * ? *', NOW(), 3, NULL, NULL, NULL, 'Send messages to SMS gateway1 _ DEFAULT', NULL, 0, 0, 1, 1, 0),
|
||||
('Get delivery reports from SMS gateway', 'Get delivery reports from SMS gateway', '0 0 0 1/1 * ? *', NOW(), 3, NULL, NULL, NULL, 'Get delivery reports from SMS gateway1 _ DEFAULT', NULL, 0, 0, 1, 1, 0);
|
||||
|
||||
INSERT INTO `m_permission`
|
||||
(`grouping` ,`code` ,`entity_name`, `action_name`, `can_maker_checker`) VALUES
|
||||
('organisation', 'READ_SMSCAMPAIGN', 'SMSCAMPAIGN', 'READ', '0'),
|
||||
('organisation', 'CREATE_SMSCAMPAIGN', 'SMSCAMPAIGN', 'CREATE', '0'),
|
||||
('organisation', 'CREATE_SMSCAMPAIGN_CHECKER', 'SMSCAMPAIGN', 'CREATE', '0'),
|
||||
('organisation', 'UPDATE_SMSCAMPAIGN', 'SMSCAMPAIGN', 'UPDATE', '0'),
|
||||
('organisation', 'UPDATE_SMSCAMPAIGN_CHECKER', 'SMSCAMPAIGN', 'UPDATE', '0'),
|
||||
('organisation', 'DELETE_SMSCAMPAIGN', 'SMSCAMPAIGN', 'DELETE', '0'),
|
||||
('organisation', 'DELETE_SMSCAMPAIGN_CHECKER', 'SMSCAMPAIGN', 'DELETE', '0'),
|
||||
('organisation', 'ACTIVATE_SMSCAMPAIGN', 'SMSCAMPAIGN', 'ACTIVATE', '0'),
|
||||
('organisation', 'CLOSE_SMSCAMPAIGN', 'SMSCAMPAIGN', 'CLOSE', '0'),
|
||||
('organisation', 'REACTIVATE_SMSCAMPAIGN', 'SMSCAMPAIGN', 'REACTIVATE', '0');
|
||||
|
||||
|
||||
|
||||
|
||||
INSERT INTO `m_code_value` (`code_id`, `code_value`, `code_description`, `order_position`, `code_score`, `is_active`, `is_mandatory`) VALUES ((SELECT `id` FROM `m_code` mc WHERE mc.code_name = "GROUPROLE" AND is_system_defined), 'Leader', 'Group Leader Role', 1, NULL, 1, 0);
|
||||
|
||||
|
||||
|
||||
|
||||
INSERT INTO `stretchy_parameter` (`parameter_name`, `parameter_variable`, `parameter_label`, `parameter_displayType`, `parameter_FormatType`, `parameter_default`, `special`, `selectOne`, `selectAll`, `parameter_sql`, `parent_id`) VALUES ('cycleXSelect', 'cycleX', 'Cycle X Number', 'text', 'number', 'n/a', NULL, NULL, NULL, NULL, NULL),
|
||||
('cycleYSelect', 'cycleY', 'Cycle Y Number', 'text', 'number', 'n/a', NULL, NULL, NULL, NULL, NULL),
|
||||
('fromXSelect', 'fromX', 'From X Number', 'text', 'number', 'n/a', NULL, NULL, NULL, NULL, NULL),
|
||||
('toYSelect', 'toY', 'To Y Number', 'text', 'number', 'n/a', NULL, NULL, NULL, NULL, NULL),
|
||||
('overdueXSelect', 'overdueX', 'Overdue X Number', 'text', 'number', 'n/a', NULL, NULL, NULL, NULL, NULL),
|
||||
('overdueYSelect', 'overdueY', 'Overdue Y Number', 'text', 'number', 'n/a', NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
|
||||
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Active Clients', 'SMS', 'NonTriggered', 'Clients', 'SELECT c.id AS "id", \r\nc.firstname AS "firstName",\r\nc.middlename AS "middleName",\r\nc.lastname AS "lastName",\r\nc.display_name AS "fullName",\r\nc.mobile_no AS "mobileNo", CONCAT(REPEAT("..", ((LENGTH(ounder.`hierarchy`) - LENGTH(\r\nREPLACE(ounder.`hierarchy`, \'.\', \'\')) - 1))), ounder.`name`) AS "officeName", \r\no.id AS "officeNumber"\r\nFROM m_office o\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(o.hierarchy, \'%\')\r\nJOIN m_client c ON c.office_id = ounder.id\r\nLEFT JOIN r_enum_value r ON r.enum_name = \'status_enum\' AND r.enum_id = c.status_enum\r\nWHERE o.id = ${officeId} AND c.status_enum = 300 AND (IFNULL(c.staff_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId})\r\nGROUP BY c.id\r\nORDER BY ounder.hierarchy, c.account_no', 'All clients with the status ‘Active’', 0, 1);
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Prospective Clients', 'SMS', 'NonTriggered', 'Clients', 'SELECT c.id AS "id", \r\nc.firstname AS "firstName",\r\nc.middlename AS "middleName",\r\nc.lastname AS "lastName",\r\nc.display_name AS "fullName",\r\nc.mobile_no AS "mobileNo", CONCAT(REPEAT("..", ((LENGTH(ounder.`hierarchy`) - LENGTH(\r\nREPLACE(ounder.`hierarchy`, \'.\', \'\')) - 1))), ounder.`name`) AS "officeName", \r\no.id AS "officeNumber"\r\nFROM m_office o\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(o.hierarchy, \'%\')\r\nJOIN m_client c ON c.office_id = ounder.id\r\nLEFT JOIN r_enum_value r ON r.enum_name = \'status_enum\' AND r.enum_id = c.status_enum\r\nLEFT JOIN m_loan l ON l.client_id = c.id\r\nWHERE o.id = ${officeId} AND c.status_enum = 300 AND (IFNULL(c.staff_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId}) AND l.client_id IS NULL\r\nGROUP BY c.id\r\nORDER BY ounder.hierarchy, c.account_no', 'All clients with the status ‘Active’ who have never had a loan before', 0, 1);
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Active Loan Clients', 'SMS', 'NonTriggered', 'Clients', 'SELECT \r\nc.id AS "id", \r\nc.firstname AS "firstName",\r\nc.middlename AS "middleName",\r\nc.lastname AS "lastName",\r\nc.display_name AS "fullName",\r\nc.mobile_no AS "mobileNo", \r\nl.principal_amount AS "loanAmount", \r\n(IFNULL(l.principal_outstanding_derived, 0) + IFNULL(l.interest_outstanding_derived, 0) + IFNULL(l.fee_charges_outstanding_derived, 0) + IFNULL(l.penalty_charges_outstanding_derived, 0)) AS "loanOutstanding",\r\nl.principal_disbursed_derived AS "loanDisbursed",\r\nounder.id AS "officeNumber", \r\nl.account_no AS "loanAccountId", \r\ngua.lastname AS "guarantorLastName", COUNT(gua.id) AS "numberOfGuarantors",\r\ng.display_name AS "groupName"\r\n\r\nFROM m_office o\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(o.hierarchy, \'%\')\r\nJOIN m_client c ON c.office_id = ounder.id\r\nJOIN m_loan l ON l.client_id = c.id\r\nJOIN m_product_loan pl ON pl.id = l.product_id\r\nLEFT JOIN m_group_client gc ON gc.client_id = c.id\r\nLEFT JOIN m_group g ON g.id = gc.group_id\r\nLEFT JOIN m_staff lo ON lo.id = l.loan_officer_id\r\nLEFT JOIN m_currency cur ON cur.code = l.currency_code\r\nLEFT JOIN m_guarantor gua ON gua.loan_id = l.id\r\nWHERE o.id = ${officeId} AND (IFNULL(l.loan_officer_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId}) AND l.loan_status_id = 300 AND (DATEDIFF(CURDATE(), l.disbursedon_date) BETWEEN ${cycleX} AND ${cycleY})\r\nGROUP BY l.id\r\nORDER BY ounder.hierarchy, l.currency_code, c.account_no, l.account_no', 'All clients with an outstanding loan', 0, 1);
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Loan in arrears', 'SMS', 'NonTriggered', 'Loan', 'SELECT \r\nmc.id AS "id", \r\nmc.firstname AS "firstName",\r\nmc.middlename AS "middleName",\r\nmc.lastname AS "lastName",\r\nmc.display_name AS "fullName",\r\nmc.mobile_no AS "mobileNo", \r\nml.principal_amount AS "loanAmount", \r\n(IFNULL(ml.principal_outstanding_derived, 0) + IFNULL(ml.interest_outstanding_derived, 0) + IFNULL(ml.fee_charges_outstanding_derived, 0) + IFNULL(ml.penalty_charges_outstanding_derived, 0)) AS "loanOutstanding",\r\nml.principal_disbursed_derived AS "loanDisbursed",\r\nlaa.overdue_since_date_derived AS "paymentDueDate",\r\nIFNULL(laa.total_overdue_derived, 0) AS "totalDue",\r\nounder.id AS "officeNumber", \r\nml.account_no AS "loanAccountId", \r\ngua.lastname AS "guarantorLastName", \r\nCOUNT(gua.id) AS "numberOfGuarantors",\r\ng.display_name AS "groupName"\r\n\r\nFROM m_office mo\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(mo.hierarchy, \'%\')\r\nINNER JOIN m_client mc ON mc.office_id=ounder.id\r\nINNER JOIN m_loan ml ON ml.client_id = mc.id\r\nINNER JOIN r_enum_value rev ON rev.enum_id=ml.loan_status_id AND rev.enum_name = \'loan_status_id\'\r\nINNER JOIN m_loan_arrears_aging laa ON laa.loan_id=ml.id\r\nLEFT JOIN m_currency cur ON cur.code = ml.currency_code\r\nLEFT JOIN m_group_client gc ON gc.client_id = mc.id\r\nLEFT JOIN m_group g ON g.id = gc.group_id\r\nLEFT JOIN m_staff lo ON lo.id = ml.loan_officer_id\r\nLEFT JOIN m_guarantor gua ON gua.loan_id = ml.id\r\nWHERE ml.loan_status_id=300 AND mo.id=${officeId} AND (IFNULL(ml.loan_officer_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId}) AND (DATEDIFF(CURDATE(), laa.overdue_since_date_derived) BETWEEN ${fromX} AND ${toY})\r\nGROUP BY ml.id\r\nORDER BY ounder.hierarchy, ml.currency_code, mc.account_no, ml.account_no', 'All clients with an outstanding loan in arrears between X and Y days', 0, 1);
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Loan payments due', 'SMS', 'NonTriggered', 'Loan', 'SELECT \r\ncl.id AS "id", \r\ncl.firstname AS "firstName",\r\ncl.middlename AS "middleName",\r\ncl.lastname AS "lastName",\r\ncl.display_name AS "fullName",\r\ncl.mobile_no AS "mobileNo", \r\nl.principal_amount AS "loanAmount",\r\nof.id AS "officeNumber",\r\n(IFNULL(l.principal_outstanding_derived, 0) + IFNULL(l.interest_outstanding_derived, 0) + IFNULL(l.fee_charges_outstanding_derived, 0) + IFNULL(l.penalty_charges_outstanding_derived, 0)) AS "loanOutstanding",\r\nl.principal_disbursed_derived AS "loanDisbursed",\r\nls.duedate AS "paymentDueDate",\r\n(IFNULL(SUM(ls.principal_amount),0) - IFNULL(SUM(ls.principal_writtenoff_derived),0)\r\n + IFNULL(SUM(ls.interest_amount),0) - IFNULL(SUM(ls.interest_writtenoff_derived),0) \r\n - IFNULL(SUM(ls.interest_waived_derived),0)\r\n + IFNULL(SUM(ls.fee_charges_amount),0) - IFNULL(SUM(ls.fee_charges_writtenoff_derived),0) \r\n - IFNULL(SUM(ls.fee_charges_waived_derived),0)\r\n + IFNULL(SUM(ls.penalty_charges_amount),0) - IFNULL(SUM(ls.penalty_charges_writtenoff_derived),0) \r\n - IFNULL(SUM(ls.penalty_charges_waived_derived),0)\r\n) AS "totalDue",\r\nlaa.total_overdue_derived AS "totalOverdue",\r\nl.account_no AS "loanAccountId",\r\ngua.lastname AS "guarantorLastName",\r\nCOUNT(gua.id) AS "numberOfGuarantors",\r\ngp.display_name AS "groupName"\r\n\r\nFROM m_office of\r\nLEFT JOIN m_client cl ON of.id = cl.office_id\r\nLEFT JOIN m_loan l ON cl.id = l.client_id\r\nLEFT JOIN m_group_client gc ON gc.client_id = cl.id\r\nLEFT JOIN m_group gp ON gp.id = l.group_id\r\nLEFT JOIN m_loan_repayment_schedule ls ON l.id = ls.loan_id\r\nLEFT JOIN m_guarantor gua ON gua.loan_id = l.id\r\nINNER JOIN m_loan_arrears_aging laa ON laa.loan_id=l.id\r\nWHERE of.id = ${officeId} AND (IFNULL(l.loan_officer_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId}) AND (DATEDIFF(CURDATE(), ls.duedate) BETWEEN ${fromX} AND ${toY}) \r\nAND (of.hierarchy LIKE CONCAT((\r\nSELECT ino.hierarchy\r\nFROM m_office ino\r\nWHERE ino.id = ${}),"%"))\r\nGROUP BY l.id\r\nORDER BY of.hierarchy, l.currency_code, cl.account_no, l.account_no', 'All clients with an unpaid installment due on their loan between X and Y days', 0, 1);
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Dormant Prospects', 'SMS', 'NonTriggered', 'Clients', 'SELECT CONCAT(REPEAT("..", ((LENGTH(ounder.`hierarchy`) - LENGTH(\r\nREPLACE(ounder.`hierarchy`, \'.\', \'\')) - 1))), ounder.`name`) AS "officeName", \r\nc.firstname AS "firstName",\r\nc.middlename AS "middleName",\r\nc.lastname AS "lastName",\r\nc.display_name AS "fullName",\r\nc.mobile_no AS "mobileNo", \r\no.id AS "officeNumber", \r\nTIMESTAMPDIFF(MONTH, c.activation_date, CURDATE()) AS "dormant"\r\nFROM m_office o\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(o.hierarchy, \'%\')\r\nJOIN m_client c ON c.office_id = ounder.id\r\nLEFT JOIN r_enum_value r ON r.enum_name = \'status_enum\' AND r.enum_id = c.status_enum\r\nLEFT JOIN m_loan l ON l.client_id = c.id\r\nWHERE o.id = ${officeId} AND c.status_enum = 300 AND (IFNULL(c.staff_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId}) AND l.client_id IS NULL AND (TIMESTAMPDIFF(MONTH, c.activation_date, CURDATE()) > 3)\r\nGROUP BY c.id\r\nORDER BY ounder.hierarchy, c.account_no', 'All individuals who have not yet received a loan but were also entered into the system more than 3 months', 0, 1);
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Active group leaders', 'SMS', 'NonTriggered', 'Clients', 'SELECT c.id AS "id", \r\nc.firstname AS "firstName",\r\nc.middlename AS "middleName",\r\nc.lastname AS "lastName",\r\nc.display_name AS "fullName",\r\nc.mobile_no AS "mobileNo", CONCAT(REPEAT("..", ((LENGTH(ounder.`hierarchy`) - LENGTH(\r\nREPLACE(ounder.`hierarchy`, \'.\', \'\')) - 1))), ounder.`name`) AS "officeName", \r\no.id AS "officeNumber"\r\nFROM m_office o\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(o.hierarchy, \'%\')\r\nJOIN m_group g ON g.office_id = ounder.id\r\nJOIN m_client c ON c.office_id = ounder.id\r\nLEFT JOIN m_group_client gc ON gc.group_id = g.id AND gc.client_id = c.id\r\nLEFT JOIN m_group_roles gr ON gr.group_id = g.id AND gr.client_id = c.id\r\nLEFT JOIN m_staff ms ON ms.id = c.staff_id\r\nLEFT JOIN r_enum_value r ON r.enum_name = \'status_enum\' AND r.enum_id = c.status_enum\r\nLEFT JOIN m_code_value cv ON cv.id = gr.role_cv_id\r\nLEFT JOIN m_code code ON code.id = cv.code_id\r\nWHERE o.id = ${officeId} AND g.status_enum = 300 AND c.status_enum = 300 AND (IFNULL(c.staff_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId}) AND code.code_name = \'GROUPROLE\' AND cv.code_value = \'Leader\'\r\nGROUP BY c.id\r\nORDER BY ounder.hierarchy, c.account_no', 'All active group chairmen', 0, 1);
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Loan payments due (Overdue Loans)', 'SMS', 'NonTriggered', 'Loan', 'SELECT \r\nmc.id AS "id", \r\nmc.firstname AS "firstName",\r\nmc.middlename AS "middleName",\r\nmc.lastname AS "lastName",\r\nmc.display_name AS "fullName",\r\nmc.mobile_no AS "mobileNo", \r\nml.principal_amount AS "loanAmount", \r\n(IFNULL(ml.principal_outstanding_derived, 0) + IFNULL(ml.interest_outstanding_derived, 0) + IFNULL(ml.fee_charges_outstanding_derived, 0) + IFNULL(ml.penalty_charges_outstanding_derived, 0)) AS "loanOutstanding",\r\nml.principal_disbursed_derived AS "loanDisbursed",\r\nlaa.overdue_since_date_derived AS "paymentDueDate",\r\n(IFNULL(SUM(ls.principal_amount),0) - IFNULL(SUM(ls.principal_writtenoff_derived),0)\r\n + IFNULL(SUM(ls.interest_amount),0) - IFNULL(SUM(ls.interest_writtenoff_derived),0) \r\n - IFNULL(SUM(ls.interest_waived_derived),0)\r\n + IFNULL(SUM(ls.fee_charges_amount),0) - IFNULL(SUM(ls.fee_charges_writtenoff_derived),0) \r\n - IFNULL(SUM(ls.fee_charges_waived_derived),0)\r\n + IFNULL(SUM(ls.penalty_charges_amount),0) - IFNULL(SUM(ls.penalty_charges_writtenoff_derived),0) \r\n - IFNULL(SUM(ls.penalty_charges_waived_derived),0)\r\n) AS "totalDue",\r\nlaa.total_overdue_derived AS "totalOverdue",\r\nounder.id AS "officeNumber", \r\nml.account_no AS "loanAccountId", \r\ngua.lastname AS "guarantorLastName", \r\nCOUNT(gua.id) AS "numberOfGuarantors",\r\ng.display_name AS "groupName"\r\n\r\nFROM m_office mo\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(mo.hierarchy, \'%\')\r\nINNER JOIN m_client mc ON mc.office_id=ounder.id\r\nINNER JOIN m_loan ml ON ml.client_id = mc.id\r\nINNER JOIN r_enum_value rev ON rev.enum_id=ml.loan_status_id AND rev.enum_name = \'loan_status_id\'\r\nINNER JOIN m_loan_arrears_aging laa ON laa.loan_id=ml.id\r\nLEFT JOIN m_loan_repayment_schedule ls ON ls.loan_id = ml.id\r\nLEFT JOIN m_currency cur ON cur.code = ml.currency_code\r\nLEFT JOIN m_group_client gc ON gc.client_id = mc.id\r\nLEFT JOIN m_group g ON g.id = gc.group_id\r\nLEFT JOIN m_staff lo ON lo.id = ml.loan_officer_id\r\nLEFT JOIN m_guarantor gua ON gua.loan_id = ml.id\r\nWHERE ml.loan_status_id=300 AND mo.id=${officeId} AND (IFNULL(ml.loan_officer_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId}) \r\nAND (DATEDIFF(CURDATE(), ls.duedate) BETWEEN ${fromX} AND ${toY})\r\nAND (DATEDIFF(CURDATE(), laa.overdue_since_date_derived) BETWEEN ${overdueX} AND ${overdueY})\r\nGROUP BY ml.id\r\nORDER BY ounder.hierarchy, ml.currency_code, mc.account_no, ml.account_no', 'Loan Payments Due between X to Y days for clients in arrears between X and Y days', 0, 1);
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Loan payments received (Active Loans)', 'SMS', 'NonTriggered', 'Loan', 'SELECT \r\nmc.id AS "id", \r\nmc.firstname AS "firstName",\r\nmc.middlename AS "middleName",\r\nmc.lastname AS "lastName",\r\nmc.display_name AS "fullName",\r\nmc.mobile_no AS "mobileNo", \r\nml.principal_amount AS "loanAmount", \r\n(IFNULL(ml.principal_outstanding_derived, 0) + IFNULL(ml.interest_outstanding_derived, 0) + IFNULL(ml.fee_charges_outstanding_derived, 0) + IFNULL(ml.penalty_charges_outstanding_derived, 0)) AS "loanOutstanding",\r\nounder.id AS "officeNumber", \r\nml.account_no AS "loanAccountNumber",\r\nSUM(lt.amount) AS "repaymentAmount"\r\nFROM m_office mo\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(mo.hierarchy, \'%\')\r\nINNER JOIN m_client mc ON mc.office_id=ounder.id\r\nINNER JOIN m_loan ml ON ml.client_id = mc.id\r\nINNER JOIN r_enum_value rev ON rev.enum_id=ml.loan_status_id AND rev.enum_name = \'loan_status_id\'\r\nINNER JOIN m_loan_transaction lt ON lt.loan_id = ml.id\r\nINNER JOIN m_appuser au ON au.id = lt.appuser_id\r\nLEFT JOIN m_loan_arrears_aging laa ON laa.loan_id=ml.id\r\nLEFT JOIN m_payment_detail mpd ON mpd.id=lt.payment_detail_id\r\nLEFT JOIN m_currency cur ON cur.code = ml.currency_code\r\nLEFT JOIN m_group_client gc ON gc.client_id = mc.id\r\nLEFT JOIN m_group g ON g.id = gc.group_id\r\nLEFT JOIN m_staff lo ON lo.id = ml.loan_officer_id\r\nLEFT JOIN m_guarantor gua ON gua.loan_id = ml.id\r\nWHERE ml.loan_status_id=300 AND mo.id=${officeId} AND (IFNULL(ml.loan_officer_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId}) AND (DATEDIFF(CURDATE(), lt.transaction_date) BETWEEN ${fromX} AND ${toY}) AND lt.is_reversed=0 AND lt.transaction_type_enum=2 AND laa.loan_id IS NULL\r\nGROUP BY ml.id\r\nORDER BY ounder.hierarchy, ml.currency_code, mc.account_no, ml.account_no', 'Payments received in the last X to Y days for any loan with the status Active (on-time)', 0, 1);
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Loan payments received (Overdue Loans)', 'SMS', 'NonTriggered', 'Loan', 'SELECT \r\nml.id AS "loanId", \r\nmc.id AS "id", \r\nmc.firstname AS "firstName",\r\nmc.middlename AS "middleName",\r\nmc.lastname AS "lastName",\r\nmc.display_name AS "fullName",\r\nmc.mobile_no AS "mobileNo", \r\nml.principal_amount AS "loanAmount", \r\n(IFNULL(ml.principal_outstanding_derived, 0) + IFNULL(ml.interest_outstanding_derived, 0) + IFNULL(ml.fee_charges_outstanding_derived, 0) + IFNULL(ml.penalty_charges_outstanding_derived, 0)) AS "loanOutstanding",\r\nounder.id AS "officeNumber", \r\nml.account_no AS "loanAccountNumber",\r\nSUM(lt.amount) AS "repaymentAmount"\r\nFROM m_office mo\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(mo.hierarchy, \'%\')\r\nINNER JOIN m_client mc ON mc.office_id=ounder.id\r\nINNER JOIN m_loan ml ON ml.client_id = mc.id\r\nINNER JOIN r_enum_value rev ON rev.enum_id=ml.loan_status_id AND rev.enum_name = \'loan_status_id\'\r\nINNER JOIN m_loan_arrears_aging laa ON laa.loan_id=ml.id\r\nINNER JOIN m_loan_transaction lt ON lt.loan_id = ml.id\r\nINNER JOIN m_appuser au ON au.id = lt.appuser_id\r\nLEFT JOIN m_payment_detail mpd ON mpd.id=lt.payment_detail_id\r\nLEFT JOIN m_currency cur ON cur.code = ml.currency_code\r\nLEFT JOIN m_group_client gc ON gc.client_id = mc.id\r\nLEFT JOIN m_group g ON g.id = gc.group_id\r\nLEFT JOIN m_staff lo ON lo.id = ml.loan_officer_id\r\nLEFT JOIN m_guarantor gua ON gua.loan_id = ml.id\r\nWHERE ml.loan_status_id=300 AND mo.id=${officeId} AND (IFNULL(ml.loan_officer_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId}) AND (DATEDIFF(CURDATE(), lt.transaction_date) BETWEEN ${fromX} AND ${toY}) AND (DATEDIFF(CURDATE(), laa.overdue_since_date_derived) BETWEEN ${overdueX} AND ${overdueY}) AND lt.is_reversed=0 AND lt.transaction_type_enum=2\r\nGROUP BY ml.id\r\nORDER BY ounder.hierarchy, ml.currency_code, mc.account_no, ml.account_no', 'Payments received in the last X to Y days for any loan with the status Overdue (arrears) between X and Y days', 0, 1);
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Happy Birthday', 'SMS', 'NonTriggered', 'Clients', 'SELECT \r\nc.id AS "id", \r\nc.firstname AS "firstName",\r\nc.middlename AS "middleName",\r\nc.lastname AS "lastName",\r\nc.display_name AS "fullName",\r\nc.mobile_no AS "mobileNo", CONCAT(REPEAT("..", ((LENGTH(ounder.`hierarchy`) - LENGTH(\r\nREPLACE(ounder.`hierarchy`, \'.\', \'\')) - 1))), ounder.`name`) AS "officeName", \r\no.id AS "officeNumber", \r\nc.date_of_birth AS "dateOfBirth",\r\nIF(c.date_of_birth IS NULL, 0, CEIL(DATEDIFF (NOW(), c.date_of_birth)/365)) AS "age"\r\nFROM m_office o\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(o.hierarchy, \'%\')\r\nJOIN m_client c ON c.office_id = ounder.id\r\nLEFT JOIN r_enum_value r ON r.enum_name = \'status_enum\' AND r.enum_id = c.status_enum\r\nLEFT JOIN m_staff ms ON ms.id = c.staff_id\r\nWHERE o.id = ${officeId} AND c.status_enum = 300 AND (IFNULL(c.staff_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId}) AND c.date_of_birth IS NOT NULL AND c.date_of_birth = CURDATE()\r\nORDER BY ounder.hierarchy, c.account_no', 'This sends a message to all clients with the status Active on their Birthday', 0, 1);
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Loan fully repaid', 'SMS', 'NonTriggered', 'Loan', 'SELECT \r\nc.id AS "id", \r\nc.firstname AS "firstName",\r\nc.middlename AS "middleName",\r\nc.lastname AS "lastName",\r\nc.display_name AS "fullName",\r\nc.mobile_no AS "mobileNo", \r\nl.principal_amount AS "loanAmount",\r\n(IFNULL(l.principal_outstanding_derived, 0) + IFNULL(l.interest_outstanding_derived, 0) + IFNULL(l.fee_charges_outstanding_derived, 0) + IFNULL(l.penalty_charges_outstanding_derived, 0)) AS "loanOutstanding",\r\nl.principal_disbursed_derived AS "loanDisbursed",\r\no.id AS "officeNumber",\r\nl.account_no AS "loanAccountId",\r\ngua.lastname AS "guarantorLastName", COUNT(gua.id) AS "numberOfGuarantors",\r\nls.duedate AS "dueDate",\r\nlaa.total_overdue_derived AS "totalDue",\r\ngp.display_name AS "groupName",\r\nl.total_repayment_derived AS "totalFullyPaid"\r\nFROM m_office o\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(o.hierarchy, \'%\')\r\nJOIN m_client c ON c.office_id = ounder.id\r\nJOIN m_loan l ON l.client_id = c.id\r\nLEFT JOIN m_staff lo ON lo.id = l.loan_officer_id\r\nLEFT JOIN m_currency cur ON cur.code = l.currency_code\r\nLEFT JOIN m_group_client gc ON gc.client_id = c.id\r\nLEFT JOIN m_group gp ON gp.id = l.group_id\r\nLEFT JOIN m_loan_repayment_schedule ls ON l.id = ls.loan_id\r\nLEFT JOIN m_guarantor gua ON gua.loan_id = l.id\r\nINNER JOIN m_loan_arrears_aging laa ON laa.loan_id=l.id\r\nWHERE o.id = ${officeId} AND (IFNULL(l.loan_officer_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId}) AND \r\n(DATEDIFF(CURDATE(), l.closedon_date) BETWEEN ${fromX} AND ${toY})\r\n AND (l.loan_status_id = 600 OR l.loan_status_id = 700)\r\nGROUP BY l.id\r\nORDER BY ounder.hierarchy, l.currency_code, c.account_no, l.account_no', 'All loans that have been fully repaid (Closed or Overpaid) in the last X to Y days', 0, 1);
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Loan outstanding after final instalment date', 'SMS', 'NonTriggered', 'Loan', 'SELECT \r\nc.id AS "id", \r\nc.firstname AS "firstName",\r\nc.middlename AS "middleName",\r\nc.lastname AS "lastName",\r\nc.display_name AS "fullName",\r\nc.mobile_no AS "mobileNo", \r\nl.principal_amount AS "loanAmount",\r\no.id AS "officeNumber",\r\n(IFNULL(l.principal_outstanding_derived, 0) + IFNULL(l.interest_outstanding_derived, 0) + IFNULL(l.fee_charges_outstanding_derived, 0) + IFNULL(l.penalty_charges_outstanding_derived, 0)) AS "loanOutstanding",\r\nl.principal_disbursed_derived AS "loanDisbursed",\r\nls.duedate AS "paymentDueDate",\r\n(IFNULL(SUM(ls.principal_amount),0) - IFNULL(SUM(ls.principal_writtenoff_derived),0)\r\n + IFNULL(SUM(ls.interest_amount),0) - IFNULL(SUM(ls.interest_writtenoff_derived),0) \r\n - IFNULL(SUM(ls.interest_waived_derived),0)\r\n + IFNULL(SUM(ls.fee_charges_amount),0) - IFNULL(SUM(ls.fee_charges_writtenoff_derived),0) \r\n - IFNULL(SUM(ls.fee_charges_waived_derived),0)\r\n + IFNULL(SUM(ls.penalty_charges_amount),0) - IFNULL(SUM(ls.penalty_charges_writtenoff_derived),0) \r\n - IFNULL(SUM(ls.penalty_charges_waived_derived),0)\r\n) AS "totalDue",\r\nlaa.total_overdue_derived AS "totalOverdue",\r\nl.account_no AS "loanAccountId",\r\ngua.lastname AS "guarantorLastName",\r\nCOUNT(gua.id) AS "numberOfGuarantors",\r\ngp.display_name AS "groupName"\r\n\r\nFROM m_office o\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(o.hierarchy, \'%\')\r\nJOIN m_client c ON c.office_id = ounder.id\r\nJOIN m_loan l ON l.client_id = c.id\r\nLEFT JOIN m_staff lo ON lo.id = l.loan_officer_id\r\nLEFT JOIN m_currency cur ON cur.code = l.currency_code\r\nLEFT JOIN m_loan_arrears_aging laa ON laa.loan_id = l.id\r\nLEFT JOIN m_group_client gc ON gc.client_id = c.id\r\nLEFT JOIN m_group gp ON gp.id = l.group_id\r\nLEFT JOIN m_loan_repayment_schedule ls ON l.id = ls.loan_id\r\nLEFT JOIN m_guarantor gua ON gua.loan_id = l.id\r\nWHERE o.id = ${officeId} AND (IFNULL(l.loan_officer_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId}) AND l.loan_status_id = 300 AND l.expected_maturedon_date < CURDATE() \r\nAND (DATEDIFF(CURDATE(), l.expected_maturedon_date) BETWEEN ${fromX} AND ${toY})\r\nGROUP BY l.id\r\nORDER BY ounder.hierarchy, l.currency_code, c.account_no, l.account_no', 'All active loans (with an outstanding balance) between X to Y days after the final instalment date on their loan schedule', 0, 1);
|
||||
|
||||
|
||||
INSERT INTO `stretchy_report_parameter` (`report_id`, `parameter_id`, `report_parameter_name`) VALUES
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Active Clients' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='OfficeIdSelectOne' AND parameter_variable = 'officeId'), 'officeId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Active Clients' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='loanOfficerIdSelectAll' AND parameter_variable = 'loanOfficerId'), 'loanOfficerId'),
|
||||
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Prospective Clients' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='OfficeIdSelectOne' AND parameter_variable = 'officeId'), 'officeId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Prospective Clients' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='loanOfficerIdSelectAll' AND parameter_variable = 'loanOfficerId'), 'loanOfficerId'),
|
||||
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Active Loan Clients' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='OfficeIdSelectOne' AND parameter_variable = 'officeId'), 'officeId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Active Loan Clients' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='loanOfficerIdSelectAll' AND parameter_variable = 'loanOfficerId'), 'loanOfficerId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Active Loan Clients' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='cycleXSelect' AND parameter_variable = 'cycleX'), 'cycleX'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Active Loan Clients' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='cycleYSelect' AND parameter_variable = 'cycleY'), 'cycleY'),
|
||||
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan in arrears' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='OfficeIdSelectOne' AND parameter_variable = 'officeId'), 'officeId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan in arrears' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='loanOfficerIdSelectAll' AND parameter_variable = 'loanOfficerId'), 'loanOfficerId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan in arrears' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='fromXSelect' AND parameter_variable = 'fromX'), 'fromX'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan in arrears' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='toYSelect' AND parameter_variable = 'toY'), 'toY'),
|
||||
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments due' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='OfficeIdSelectOne' AND parameter_variable = 'officeId'), 'officeId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments due' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='loanOfficerIdSelectAll' AND parameter_variable = 'loanOfficerId'), 'loanOfficerId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments due' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='fromXSelect' AND parameter_variable = 'fromX'), 'fromX'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments due' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='toYSelect' AND parameter_variable = 'toY'), 'toY'),
|
||||
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Dormant Prospects' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='OfficeIdSelectOne' AND parameter_variable = 'officeId'), 'officeId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Dormant Prospects' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='loanOfficerIdSelectAll' AND parameter_variable = 'loanOfficerId'), 'loanOfficerId'),
|
||||
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Active group leaders' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='OfficeIdSelectOne' AND parameter_variable = 'officeId'), 'officeId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Active group leaders' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='loanOfficerIdSelectAll' AND parameter_variable = 'loanOfficerId'), 'loanOfficerId'),
|
||||
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments due (Overdue Loans)' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='OfficeIdSelectOne' AND parameter_variable = 'officeId'), 'officeId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments due (Overdue Loans)' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='loanOfficerIdSelectAll' AND parameter_variable = 'loanOfficerId'), 'loanOfficerId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments due (Overdue Loans)' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='fromXSelect' AND parameter_variable = 'fromX'), 'fromX'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments due (Overdue Loans)' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='toYSelect' AND parameter_variable = 'toY'), 'toY'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments due (Overdue Loans)' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='overdueXSelect' AND parameter_variable = 'overdueX'), 'overdueX'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments due (Overdue Loans)' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='overdueYSelect' AND parameter_variable = 'overdueY'), 'overdueY'),
|
||||
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments received (Active Loans)' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='OfficeIdSelectOne' AND parameter_variable = 'officeId'), 'officeId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments received (Active Loans)' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='loanOfficerIdSelectAll' AND parameter_variable = 'loanOfficerId'), 'loanOfficerId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments received (Active Loans)' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='fromXSelect' AND parameter_variable = 'fromX'), 'fromX'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments received (Active Loans)' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='toYSelect' AND parameter_variable = 'toY'), 'toY'),
|
||||
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments received (Overdue Loans)' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='OfficeIdSelectOne' AND parameter_variable = 'officeId'), 'officeId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments received (Overdue Loans)' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='loanOfficerIdSelectAll' AND parameter_variable = 'loanOfficerId'), 'loanOfficerId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments received (Overdue Loans)' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='fromXSelect' AND parameter_variable = 'fromX'), 'fromX'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments received (Overdue Loans)' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='toYSelect' AND parameter_variable = 'toY'), 'toY'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments received (Overdue Loans)' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='overdueXSelect' AND parameter_variable = 'overdueX'), 'overdueX'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan payments received (Overdue Loans)' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='overdueYSelect' AND parameter_variable = 'overdueY'), 'overdueY'),
|
||||
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Happy Birthday' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='OfficeIdSelectOne' AND parameter_variable = 'officeId'), 'officeId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Happy Birthday' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='loanOfficerIdSelectAll' AND parameter_variable = 'loanOfficerId'), 'loanOfficerId'),
|
||||
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan fully repaid' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='OfficeIdSelectOne' AND parameter_variable = 'officeId'), 'officeId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan fully repaid' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='loanOfficerIdSelectAll' AND parameter_variable = 'loanOfficerId'), 'loanOfficerId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan fully repaid' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='fromXSelect' AND parameter_variable = 'fromX'), 'fromX'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan fully repaid' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='toYSelect' AND parameter_variable = 'toY'), 'toY'),
|
||||
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan outstanding after final instalment date' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='OfficeIdSelectOne' AND parameter_variable = 'officeId'), 'officeId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan outstanding after final instalment date' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='loanOfficerIdSelectAll' AND parameter_variable = 'loanOfficerId'), 'loanOfficerId'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan outstanding after final instalment date' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='fromXSelect' AND parameter_variable = 'fromX'), 'fromX'),
|
||||
((SELECT id FROM stretchy_report WHERE report_name='Loan outstanding after final instalment date' AND report_type = 'SMS'), (SELECT id FROM stretchy_parameter WHERE parameter_name='toYSelect' AND parameter_variable = 'toY'), 'toY');
|
||||
|
||||
|
||||
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES
|
||||
('Loan Repayment', 'SMS', 'Triggered', NULL, 'select ml.id as loanId,mc.id, mc.firstname, ifnull(mc.middlename,\'\') as middlename, mc.lastname, mc.display_name as FullName, mobile_no as mobileNo, mc.group_name as GroupName, round(ml.principal_amount, ml.currency_digits) as LoanAmount, round(ml.`total_outstanding_derived`, ml.currency_digits) as LoanOutstanding,\nml.`account_no` as LoanAccountId, round(mlt.amountPaid, ml.currency_digits) as repaymentAmount\nFROM m_office mo\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(mo.hierarchy, \'%\')\nAND ounder.hierarchy like CONCAT(\'.\', \'%\')\nLEFT JOIN (\n select \n ml.id as loanId, \n ifnull(mc.id,mc2.id) as id, \n ifnull(mc.firstname,mc2.firstname) as firstname, \n ifnull(mc.middlename,ifnull(mc2.middlename,(\'\'))) as middlename, \n ifnull(mc.lastname,mc2.lastname) as lastname, \n ifnull(mc.display_name,mc2.display_name) as display_name, \n ifnull(mc.status_enum,mc2.status_enum) as status_enum,\n ifnull(mc.mobile_no,mc2.mobile_no) as mobile_no,\n ifnull(mg.office_id,mc2.office_id) as office_id,\n ifnull(mg.staff_id,mc2.staff_id) as staff_id,\n mg.id as group_id, \nmg.display_name as group_name\n from\n m_loan ml\n left join m_group mg on mg.id = ml.group_id\n left join m_group_client mgc on mgc.group_id = mg.id\n left join m_client mc on mc.id = mgc.client_id\n left join m_client mc2 on mc2.id = ml.client_id\n order by loanId\n ) mc on mc.office_id = ounder.id\nright join m_loan as ml on mc.loanId = ml.id\nright join(\nselect mlt.amount as amountPaid,mlt.id,mlt.loan_id\nfrom m_loan_transaction mlt\nwhere mlt.is_reversed = 0 \ngroup by mlt.loan_id\n) as mlt on mlt.loan_id = ml.id\nright join m_loan_repayment_schedule as mls1 on ml.id = mls1.loan_id and mls1.`completed_derived` = 0\nand mls1.installment = (SELECT MIN(installment) from m_loan_repayment_schedule where loan_id = ml.id and duedate <= CURDATE() and completed_derived=0)\nwhere mc.status_enum = 300 and mobile_no is not null and ml.`loan_status_id` = 300\nand (mo.id = ${officeId} or ${officeId} = -1)\nand (mc.staff_id = ${loanOfficerId} or ${loanOfficerId} = -1)\nand (ml.loan_type_enum = ${loanType} or ${loanType} = -1)\nand ml.id in (select mla.loan_id from m_loan_arrears_aging mla)\ngroup by ml.id', 'Loan Repayment', 0, 0);
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES
|
||||
('Loan Approved', 'SMS', 'Triggered', NULL, 'SELECT mc.id, mc.firstname, mc.middlename as middlename, mc.lastname, mc.display_name as FullName, mc.mobile_no as mobileNo, mc.group_name as GroupName, mo.name as officename, ml.id as loanId, ml.account_no as accountnumber, ml.principal_amount_proposed as loanamount, ml.annual_nominal_interest_rate as annualinterestrate FROM m_office mo JOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(mo.hierarchy, \'%\') AND ounder.hierarchy like CONCAT(\'.\', \'%\') LEFT JOIN ( select ml.id as loanId, ifnull(mc.id,mc2.id) as id, ifnull(mc.firstname,mc2.firstname) as firstname, ifnull(mc.middlename,ifnull(mc2.middlename,(\'\'))) as middlename, ifnull(mc.lastname,mc2.lastname) as lastname, ifnull(mc.display_name,mc2.display_name) as display_name, ifnull(mc.status_enum,mc2.status_enum) as status_enum, ifnull(mc.mobile_no,mc2.mobile_no) as mobile_no, ifnull(mg.office_id,mc2.office_id) as office_id, ifnull(mg.staff_id,mc2.staff_id) as staff_id, mg.id as group_id, mg.display_name as group_name from m_loan ml left join m_group mg on mg.id = ml.group_id left join m_group_client mgc on mgc.group_id = mg.id left join m_client mc on mc.id = mgc.client_id left join m_client mc2 on mc2.id = ml.client_id order by loanId ) mc on mc.office_id = ounder.id left join m_loan ml on ml.id = mc.loanId WHERE mc.status_enum = 300 and mc.mobile_no is not null and (mo.id = ${officeId} or ${officeId} = -1) and (mc.staff_id = ${loanOfficerId} or ${loanOfficerId} = -1)and (ml.id = ${loanId} or ${loanId} = -1)and (mc.id = ${clientId} or ${clientId} = -1)and (mc.group_id = ${groupId} or ${groupId} = -1)and (ml.loan_type_enum = ${loanType} or ${loanType} = -1)', 'Loan and client data of approved loan', 0, 0);
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES
|
||||
('Loan Rejected', 'SMS', 'Triggered', NULL, 'SELECT mc.id, mc.firstname, mc.middlename as middlename, mc.lastname, mc.display_name as FullName, mc.mobile_no as mobileNo, mc.group_name as GroupName, mo.name as officename, ml.id as loanId, ml.account_no as accountnumber, ml.principal_amount_proposed as loanamount, ml.annual_nominal_interest_rate as annualinterestrate FROM m_office mo JOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(mo.hierarchy, \'%\') AND ounder.hierarchy like CONCAT(\'.\', \'%\') LEFT JOIN ( select ml.id as loanId, ifnull(mc.id,mc2.id) as id, ifnull(mc.firstname,mc2.firstname) as firstname, ifnull(mc.middlename,ifnull(mc2.middlename,(\'\'))) as middlename, ifnull(mc.lastname,mc2.lastname) as lastname, ifnull(mc.display_name,mc2.display_name) as display_name, ifnull(mc.status_enum,mc2.status_enum) as status_enum, ifnull(mc.mobile_no,mc2.mobile_no) as mobile_no, ifnull(mg.office_id,mc2.office_id) as office_id, ifnull(mg.staff_id,mc2.staff_id) as staff_id, mg.id as group_id, mg.display_name as group_name from m_loan ml left join m_group mg on mg.id = ml.group_id left join m_group_client mgc on mgc.group_id = mg.id left join m_client mc on mc.id = mgc.client_id left join m_client mc2 on mc2.id = ml.client_id order by loanId ) mc on mc.office_id = ounder.id left join m_loan ml on ml.id = mc.loanId WHERE mc.status_enum = 300 and mc.mobile_no is not null and (mo.id = ${officeId} or ${officeId} = -1) and (mc.staff_id = ${loanOfficerId} or ${loanOfficerId} = -1) and (ml.id = ${loanId} or ${loanId} = -1) and (mc.id = ${clientId} or ${clientId} = -1) and (mc.group_id = ${groupId} or ${groupId} = -1) and (ml.loan_type_enum = ${loanType} or ${loanType} = -1)', 'Loan and client data of rejected loan', 0, 0);
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `use_report`) VALUES
|
||||
('Client Rejected', 'SMS', 'Triggered', 'Clients', 'SELECT c.id AS "id", \r\nc.firstname AS "firstName",\r\nc.middlename AS "middleName",\r\nc.lastname AS "lastName",\r\nc.display_name AS "fullName",\r\nc.mobile_no AS "mobileNo", CONCAT(REPEAT("..", ((LENGTH(ounder.`hierarchy`) - LENGTH(\r\nREPLACE(ounder.`hierarchy`, \'.\', \'\')) - 1))), ounder.`name`) AS "officeName", \r\no.id AS "officeNumber"\r\nFROM m_office o\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(o.hierarchy, \'%\')\r\nJOIN m_client c ON c.office_id = ounder.id\r\nLEFT JOIN r_enum_value r ON r.enum_name = \'status_enum\' AND r.enum_id = c.status_enum\r\nWHERE o.id = ${officeId} AND c.id = ${clientId} AND (IFNULL(c.staff_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId})', 'Client Rejection', '1'),
|
||||
('Client Activated', 'SMS', 'Triggered', 'Clients', 'SELECT c.id AS "id", \r\nc.firstname AS "firstName",\r\nc.middlename AS "middleName",\r\nc.lastname AS "lastName",\r\nc.display_name AS "fullName",\r\nc.mobile_no AS "mobileNo", CONCAT(REPEAT("..", ((LENGTH(ounder.`hierarchy`) - LENGTH(\r\nREPLACE(ounder.`hierarchy`, \'.\', \'\')) - 1))), ounder.`name`) AS "officeName", \r\no.id AS "officeNumber"\r\nFROM m_office o\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(o.hierarchy, \'%\')\r\nJOIN m_client c ON c.office_id = ounder.id\r\nLEFT JOIN r_enum_value r ON r.enum_name = \'status_enum\' AND r.enum_id = c.status_enum\r\nWHERE o.id = ${officeId} AND c.id = ${clientId} AND (IFNULL(c.staff_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId})', 'Client Activation', '1'),
|
||||
('Savings Rejected', 'SMS', 'Triggered', 'Savings', 'SELECT \r\nc.id AS "id",\r\nc.firstname AS "firstName",\r\nc.middlename AS "middleName",\r\nc.lastname AS "lastName",\r\nc.display_name AS "fullName",\r\nc.mobile_no AS "mobileNo",\r\ns.account_no AS "savingsAccountNo",\r\nounder.id AS "officeNumber",\r\nounder.name AS "officeName"\r\n\r\nFROM m_office o\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(o.hierarchy, \'%\')\r\nJOIN m_client c ON c.office_id = ounder.id\r\nJOIN m_savings_account s ON s.client_id = c.id\r\nJOIN m_savings_product sp ON sp.id = s.product_id\r\nLEFT JOIN m_staff st ON st.id = s.field_officer_id\r\nLEFT JOIN m_currency cur ON cur.code = s.currency_code\r\nWHERE o.id = ${officeId} AND (IFNULL(s.field_officer_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId}) AND s.id = ${savingsId}', 'Savings Rejected', '1'),
|
||||
('Savings Activated', 'SMS', 'Triggered', 'Savings', 'SELECT \r\nc.id AS "id",\r\nc.firstname AS "firstName",\r\nc.middlename AS "middleName",\r\nc.lastname AS "lastName",\r\nc.display_name AS "fullName",\r\nc.mobile_no AS "mobileNo",\r\ns.account_no AS "savingsAccountNo",\r\nounder.id AS "officeNumber",\r\nounder.name AS "officeName"\r\n\r\nFROM m_office o\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(o.hierarchy, \'%\')\r\nJOIN m_client c ON c.office_id = ounder.id\r\nJOIN m_savings_account s ON s.client_id = c.id\r\nJOIN m_savings_product sp ON sp.id = s.product_id\r\nLEFT JOIN m_staff st ON st.id = s.field_officer_id\r\nLEFT JOIN m_currency cur ON cur.code = s.currency_code\r\nWHERE o.id = ${officeId} AND (IFNULL(s.field_officer_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId}) AND s.id = ${savingsId}', 'Savings Activation', '1');
|
||||
|
||||
INSERT INTO `r_enum_value` (`enum_name`, `enum_id`, `enum_message_property`, `enum_value`, `enum_type`)
|
||||
VALUES ('loan_type_enum', '-1', 'All', 'All', '0');
|
||||
INSERT INTO `r_enum_value` (`enum_name`, `enum_id`, `enum_message_property`, `enum_value`, `enum_type`)
|
||||
VALUES ('loan_type_enum', '1', 'Individual Loan', 'Individual Loan', '0');
|
||||
INSERT INTO `r_enum_value` (`enum_name`, `enum_id`, `enum_message_property`, `enum_value`, `enum_type`)
|
||||
VALUES ('loan_type_enum', '2', 'Group Loan', 'Group Loan', '0');
|
||||
|
||||
|
||||
INSERT INTO `stretchy_parameter` (`parameter_name`, `parameter_variable`, `parameter_label`, `parameter_displayType`, `parameter_FormatType`, `parameter_default`, `selectAll`, `parameter_sql`, `parent_id`)
|
||||
VALUES ('DefaultLoan', 'loanId', 'Loan', 'none', 'number', '-1', 'Y', 'select ml.id \nfrom m_loan ml \nleft join m_client mc on mc.id = ml.client_id \nleft join m_office mo on mo.id = mc.office_id \nwhere mo.id = ${officeId} or ${officeId} = -1', '5');
|
||||
INSERT INTO `stretchy_parameter` (`parameter_name`, `parameter_variable`, `parameter_label`, `parameter_displayType`, `parameter_FormatType`, `parameter_default`, `selectAll`, `parameter_sql`, `parent_id`)
|
||||
VALUES ('DefaultClient', 'clientId', 'Client', 'none', 'number', '-1', 'Y', 'select mc.id \nfrom m_client mc\n left join m_office on mc.office_id = mo.id\n where mo.id = ${officeId} or ${officeId} = -1', '5');
|
||||
INSERT INTO `stretchy_parameter` (`parameter_name`, `parameter_variable`, `parameter_label`, `parameter_displayType`, `parameter_FormatType`, `parameter_default`, `selectAll`, `parameter_sql`, `parent_id`)
|
||||
VALUES ('DefaultGroup', 'groupId', 'Group', 'none', 'number', '-1', 'Y', 'select mg.id \nfrom m_group mg\nleft join m_office mo on mg.office_id = mo.id\nwhere mo.id = ${officeId} or ${officeId} = -1', '5');
|
||||
INSERT INTO `stretchy_parameter` (`parameter_name`, `parameter_variable`, `parameter_label`, `parameter_displayType`, `parameter_FormatType`, `parameter_default`, `selectAll`, `parameter_sql`, `parent_id`)
|
||||
VALUES ('SelectLoanType', 'loanType', 'Loan Type', 'select', 'number', '-1', 'Y', "select\nenum_id as id,\nenum_value as value\nfrom r_enum_value\nwhere enum_name = 'loan_type_enum'", NULL);
|
||||
INSERT INTO `stretchy_parameter` (`parameter_name`, `parameter_variable`, `parameter_label`, `parameter_displayType`, `parameter_FormatType`, `parameter_default`, `special`, `selectOne`, `selectAll`, `parameter_sql`, `parent_id`) VALUES
|
||||
('DefaultSavings', 'savingsId', 'Savings', 'none', 'number', '-1', NULL, NULL, 'Y', NULL, 5);
|
||||
INSERT INTO `mifostenant-default`.`stretchy_parameter` (`parameter_name`, `parameter_variable`, `parameter_label`, `parameter_displayType`, `parameter_FormatType`, `parameter_default`, `selectAll`, `parameter_sql`, `parent_id`) VALUES ('DefaultSavingsTransactionId', 'savingsTransactionId', 'Savings Transaction', 'none', 'number', '-1', 'Y', NULL, '5');
|
||||
|
||||
SET @LRej = (select id from `stretchy_report` where `report_name`='Loan Rejected');
|
||||
SET @LApp = (select id from `stretchy_report` where `report_name`='Loan Approved');
|
||||
SET @LRep = (select id from `stretchy_report` where `report_name`='Loan Repayment');
|
||||
SET @Office = (select id from `stretchy_parameter` where `parameter_name`='OfficeIdSelectOne');
|
||||
SET @loanOfficer = (select id from `stretchy_parameter` where `parameter_name`='loanOfficerIdSelectAll');
|
||||
SET @DLoan = (select id from `stretchy_parameter` where `parameter_name`='DefaultLoan');
|
||||
SET @DClient = (select id from `stretchy_parameter` where `parameter_name`='DefaultClient');
|
||||
SET @DGroup = (select id from `stretchy_parameter` where `parameter_name`='DefaultGroup');
|
||||
SET @LoanType = (select id from `stretchy_parameter` where `parameter_name`='SelectLoanType');
|
||||
|
||||
INSERT IGNORE INTO `stretchy_report_parameter` (`report_id`, `parameter_id`, `report_parameter_name`)
|
||||
VALUES (@LRej, @Office, 'officeId'),
|
||||
(@LApp, @Office, 'officeId'),
|
||||
(@LRep, @Office, 'officeId'),
|
||||
(@LRej, @loanOfficer, 'loanOfficerId'),
|
||||
(@LApp, @loanOfficer, 'loanOfficerId'),
|
||||
(@LRep, @loanOfficer, 'loanOfficerId'),
|
||||
(@LRej, @DLoan, 'loanId'),
|
||||
(@LApp, @DLoan, 'loanId'),
|
||||
(@LRej, @DClient, 'clientId'),
|
||||
(@LApp, @DClient, 'clientId'),
|
||||
(@LRej, @DGroup, 'groupId'),
|
||||
(@LApp, @DGroup, 'groupId'),
|
||||
(@LRej, @LoanType, 'loanType'),
|
||||
(@LApp, @LoanType, 'loanType'),
|
||||
(@LRep, @LoanType, 'loanType');
|
||||
|
||||
SET @CRej = (select id from `stretchy_report` where `report_name`='Client Rejected');
|
||||
SET @CAct = (select id from `stretchy_report` where `report_name`='Client Activated');
|
||||
SET @SRej = (select id from `stretchy_report` where `report_name`='Savings Rejected');
|
||||
SET @SAct = (select id from `stretchy_report` where `report_name`='Savings Activated');
|
||||
|
||||
SET @Office = (select id from `stretchy_parameter` where `parameter_name`='OfficeIdSelectOne');
|
||||
SET @fieldOfficer = (select id from `stretchy_parameter` where `parameter_name`='loanOfficerIdSelectAll');
|
||||
SET @DClient = (select id from `stretchy_parameter` where `parameter_name`='DefaultClient');
|
||||
SET @DSavings = (select id from `stretchy_parameter` where `parameter_name`='DefaultSavings');
|
||||
|
||||
INSERT INTO `stretchy_report_parameter` (`report_id`, `parameter_id`, `report_parameter_name`) VALUES
|
||||
(@CRej, @Office, 'officeId'),
|
||||
(@CAct, @Office, 'officeId'),
|
||||
(@CRej, @fieldOfficer, 'loanOfficerId'),
|
||||
(@CAct, @fieldOfficer, 'loanOfficerId'),
|
||||
(@CRej, @DClient, 'clientId'),
|
||||
(@CAct, @DClient, 'clientId'),
|
||||
|
||||
(@SRej, @Office, 'officeId'),
|
||||
(@SRej, @fieldOfficer, 'loanOfficerId'),
|
||||
(@SRej, @DSavings, 'savingsId'),
|
||||
(@SAct, @Office, 'officeId'),
|
||||
(@SAct, @fieldOfficer, 'loanOfficerId'),
|
||||
(@SAct, @DSavings, 'savingsId');
|
||||
|
||||
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Savings Deposit', 'SMS', 'Triggered', NULL, 'SELECT sc.savingsId AS savingsId, sc.id AS clientId, sc.firstname, IFNULL(sc.middlename,\'\') AS middlename, sc.lastname, sc.display_name AS FullName, sc.mobile_no AS mobileNo,\r\nms.`account_no` AS savingsAccountNo, ROUND(mst.amountPaid, ms.currency_digits) AS depositAmount, ms.account_balance_derived AS balance, \r\nmst.transactionDate AS transactionDate\r\nFROM m_office mo\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(mo.hierarchy, \'%\') AND ounder.hierarchy LIKE CONCAT(\'.\', \'%\')\r\nLEFT JOIN (\r\nSELECT \r\n sa.id AS savingsId, mc.id AS id, mc.firstname AS firstname, mc.middlename AS middlename, mc.lastname AS lastname, \r\n mc.display_name AS display_name, mc.status_enum AS status_enum, \r\n mc.mobile_no AS mobile_no, mc.office_id AS office_id, \r\n mc.staff_id AS staff_id\r\nFROM\r\nm_savings_account sa\r\nLEFT JOIN m_client mc ON mc.id = sa.client_id\r\nORDER BY savingsId) sc ON sc.office_id = ounder.id\r\nRIGHT JOIN m_savings_account AS ms ON sc.savingsId = ms.id\r\nRIGHT JOIN(\r\nSELECT st.amount AS amountPaid, st.id, st.savings_account_id, st.id AS savingsTransactionId, st.transaction_date AS transactionDate\r\nFROM m_savings_account_transaction st\r\nWHERE st.is_reversed = 0\r\nGROUP BY st.savings_account_id\r\n) AS mst ON mst.savings_account_id = ms.id\r\nWHERE sc.mobile_no IS NOT NULL AND (mo.id = ${officeId} OR ${officeId} = -1) AND (sc.staff_id = ${loanOfficerId} OR ${loanOfficerId} = -1) AND mst.savingsTransactionId = ${savingsTransactionId}', 'Savings Deposit', 0, 1),
|
||||
('Savings Withdrawal', 'SMS', 'Triggered', NULL, 'SELECT sc.savingsId AS savingsId, sc.id AS clientId, sc.firstname, IFNULL(sc.middlename,\'\') AS middlename, sc.lastname, sc.display_name AS FullName, sc.mobile_no AS mobileNo,\r\nms.`account_no` AS savingsAccountNo, ROUND(mst.amountPaid, ms.currency_digits) AS withdrawAmount, ms.account_balance_derived AS balance, \r\nmst.transactionDate AS transactionDate\r\nFROM m_office mo\r\nJOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(mo.hierarchy, \'%\') AND ounder.hierarchy LIKE CONCAT(\'.\', \'%\')\r\nLEFT JOIN (\r\nSELECT \r\n sa.id AS savingsId, mc.id AS id, mc.firstname AS firstname, mc.middlename AS middlename, mc.lastname AS lastname, \r\n mc.display_name AS display_name, mc.status_enum AS status_enum, \r\n mc.mobile_no AS mobile_no, mc.office_id AS office_id, \r\n mc.staff_id AS staff_id\r\nFROM\r\nm_savings_account sa\r\nLEFT JOIN m_client mc ON mc.id = sa.client_id\r\nORDER BY savingsId) sc ON sc.office_id = ounder.id\r\nRIGHT JOIN m_savings_account AS ms ON sc.savingsId = ms.id\r\nRIGHT JOIN(\r\nSELECT st.amount AS amountPaid, st.id, st.savings_account_id, st.id AS savingsTransactionId, st.transaction_date AS transactionDate\r\nFROM m_savings_account_transaction st\r\nWHERE st.is_reversed = 0\r\nGROUP BY st.savings_account_id\r\n) AS mst ON mst.savings_account_id = ms.id\r\nWHERE sc.mobile_no IS NOT NULL AND (mo.id = ${officeId} OR ${officeId} = -1) AND (sc.staff_id = ${loanOfficerId} OR ${loanOfficerId} = -1) AND mst.savingsTransactionId = ${savingsTransactionId}', 'Savings Withdrawal', 0, 1);
|
||||
|
||||
|
||||
SET @SDep = (select id from `stretchy_report` where `report_name`='Savings Deposit');
|
||||
SET @SWith = (select id from `stretchy_report` where `report_name`='Savings Withdrawal');
|
||||
|
||||
SET @savingsTransaction = (select id from `stretchy_parameter` where `parameter_name`='DefaultSavingsTransactionId');
|
||||
|
||||
INSERT IGNORE INTO `stretchy_report_parameter` (`report_id`, `parameter_id`, `report_parameter_name`) VALUES
|
||||
(@SDep, @Office, 'officeId'),
|
||||
(@SDep, @loanOfficer, 'loanOfficerId'),
|
||||
(@SDep, @savingsTransaction, 'savingsTransactionId'),
|
||||
(@SWith, @Office, 'officeId'),
|
||||
(@SWith, @loanOfficer, 'loanOfficerId'),
|
||||
(@SWith, @savingsTransaction, 'savingsTransactionId');
|
||||
|
||||
INSERT INTO `c_external_service` (`name`) VALUES ('MESSAGE_GATEWAY');
|
||||
|
||||
SET @EId = (SELECT `id` FROM `c_external_service` WHERE name = 'MESSAGE_GATEWAY');
|
||||
|
||||
INSERT INTO `c_external_service_properties` (`name`, `value`, `external_service_id`) VALUES
|
||||
('host_name', 'localhost', @EId),
|
||||
('port_number', '9191', @EId),
|
||||
('end_point', '/', @EId),
|
||||
('tenant_app_key', NULL, @EId);
|
||||
Reference in New Issue
Block a user