http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/domain/SmsMessageAssembler.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/domain/SmsMessageAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/domain/SmsMessageAssembler.java index 32a56e1..695edfb 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/domain/SmsMessageAssembler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/domain/SmsMessageAssembler.java @@ -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) {
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/domain/SmsMessageRepository.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/domain/SmsMessageRepository.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/domain/SmsMessageRepository.java index 4d9768a..9dadb59 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/domain/SmsMessageRepository.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/domain/SmsMessageRepository.java @@ -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); } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/domain/SmsMessageStatusType.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/domain/SmsMessageStatusType.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/domain/SmsMessageStatusType.java index 72dce38..a97c2c6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/domain/SmsMessageStatusType.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/domain/SmsMessageStatusType.java @@ -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; http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/exception/SmsCountryCodeNotFoundException.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/exception/SmsCountryCodeNotFoundException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/exception/SmsCountryCodeNotFoundException.java new file mode 100644 index 0000000..bfdbaad --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/exception/SmsCountryCodeNotFoundException.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.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"); + } +} http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/scheduler/SmsMessageScheduledJobService.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/scheduler/SmsMessageScheduledJobService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/scheduler/SmsMessageScheduledJobService.java new file mode 100644 index 0000000..8d3e545 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/scheduler/SmsMessageScheduledJobService.java @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.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(); +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/scheduler/SmsMessageScheduledJobServiceImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/scheduler/SmsMessageScheduledJobServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/scheduler/SmsMessageScheduledJobServiceImpl.java new file mode 100644 index 0000000..3e23a10 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/scheduler/SmsMessageScheduledJobServiceImpl.java @@ -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); + } +} http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/service/SmsReadPlatformService.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/service/SmsReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/service/SmsReadPlatformService.java index db330da..68a9a99 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/service/SmsReadPlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/service/SmsReadPlatformService.java @@ -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); } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/service/SmsReadPlatformServiceImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/service/SmsReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/service/SmsReadPlatformServiceImpl.java index c4fd088..5ad0eac 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/service/SmsReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/service/SmsReadPlatformServiceImpl.java @@ -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); + } + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/Client.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/Client.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/Client.java index 0530452..5e82970 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/Client.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/Client.java @@ -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;} } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientTransaction.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientTransaction.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientTransaction.java index c8e7266..b7656f8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientTransaction.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientTransaction.java @@ -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); } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java index 3c620ab..5db7a02 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java @@ -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; + } } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java index b5f5258..9532b52 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/BusinessEventNotificationConstants.java @@ -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; } } + } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java index 0b6fbf1..c236e37 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java @@ -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 http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java index c1b0f2c..15e23cb 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java @@ -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();} } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java index 3dc1cb7..0da6393 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java @@ -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 http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/exception/InvalidLoanTypeException.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/exception/InvalidLoanTypeException.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/exception/InvalidLoanTypeException.java new file mode 100644 index 0000000..6c64060 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/exception/InvalidLoanTypeException.java @@ -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); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java index b697797..221273f 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java @@ -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()) // http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java index 75a44ea..46d9795 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java @@ -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); } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/portfolio/paymentdetail/domain/PaymentDetail.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/paymentdetail/domain/PaymentDetail.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/paymentdetail/domain/PaymentDetail.java index c02bc9d..be39011 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/paymentdetail/domain/PaymentDetail.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/paymentdetail/domain/PaymentDetail.java @@ -115,4 +115,5 @@ public final class PaymentDetail extends AbstractPersistableCustom<Long> { return this.paymentType; } + public String getReceiptNumber() { return this.receiptNumber; } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java index 6426026..ae1b0f4 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java @@ -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; + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/911cab85/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java index 56e6485..c623709 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java @@ -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 ; + } } \ No newline at end of file
