diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/DateUtils.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/DateUtils.java index f402f2016..dd7fc4a52 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/DateUtils.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/DateUtils.java @@ -5,9 +5,17 @@ */ package org.mifosplatform.infrastructure.core.service; +import java.util.ArrayList; +import java.util.List; + +import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.LocalDate; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.mifosplatform.infrastructure.core.data.ApiParameterError; import org.mifosplatform.infrastructure.core.domain.MifosPlatformTenant; +import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; public class DateUtils { @@ -27,4 +35,19 @@ public class DateUtils { return today; } + public static LocalDate parseLocalDate(final String stringDate, final String pattern) { + + try { + DateTimeFormatter dateStringFormat = DateTimeFormat.forPattern(pattern); + DateTime dateTime = dateStringFormat.parseDateTime(stringDate); + return dateTime.toLocalDate(); + } catch (IllegalArgumentException e) { + List dataValidationErrors = new ArrayList(); + ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.date.pattern", "The parameter date (" + + stringDate + ") is invalid w.r.t. pattern " + pattern, "date", stringDate, pattern); + dataValidationErrors.add(error); + throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", + dataValidationErrors); + } + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/api/CollectionSheetApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/api/CollectionSheetApiResource.java new file mode 100644 index 000000000..c21190920 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/api/CollectionSheetApiResource.java @@ -0,0 +1,75 @@ +package org.mifosplatform.portfolio.collectionsheet.api; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +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.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper; +import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; +import org.mifosplatform.infrastructure.core.serialization.ToApiJsonSerializer; +import org.mifosplatform.infrastructure.core.service.DateUtils; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.mifosplatform.portfolio.collectionsheet.data.JLGCollectionSheetData; +import org.mifosplatform.portfolio.collectionsheet.service.CollectionSheetReadPlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +/* + * At present API supports groups/{groupId} + * Future version supports staffs/{staffId} + * Future version supports offices/{officeId} + */ + +@Path("/groups/{groupId}/collectionsheet") +@Component +@Scope("singleton") +public class CollectionSheetApiResource { + + private final Set COLLECTIONSHEET_DATA_PARAMETERS = new HashSet(Arrays.asList("dueDate", "groups")); + /* + * dueDate format is ISO 8601 Calendar Date (YYYYMMDD) + */ + private final String datePattern = "YYYYMMDD"; + private final PlatformSecurityContext context; + private final CollectionSheetReadPlatformService collectionSheetReadPlatformService; + private final ToApiJsonSerializer toApiJsonSerializer; + private final ApiRequestParameterHelper apiRequestParameterHelper; + + @Autowired + public CollectionSheetApiResource(final PlatformSecurityContext context, + final CollectionSheetReadPlatformService collectionSheetReadPlatformService, + final ToApiJsonSerializer toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper) { + + this.context = context; + this.collectionSheetReadPlatformService = collectionSheetReadPlatformService; + this.toApiJsonSerializer = toApiJsonSerializer; + this.apiRequestParameterHelper = apiRequestParameterHelper; + + } + + @GET + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String collectionSheetData(@Context final UriInfo uriInfo, @PathParam("groupId") final Long groupId, + @QueryParam("dueDate") final String dueDate) { + + this.context.authenticatedUser().validateHasReadPermission("COLLECTIONSHEET"); + final LocalDate localDate = DateUtils.parseLocalDate(dueDate, this.datePattern); + final JLGCollectionSheetData collectionSheet = this.collectionSheetReadPlatformService.retriveCollectionSheet(localDate, groupId); + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + return this.toApiJsonSerializer.serialize(settings, collectionSheet, this.COLLECTIONSHEET_DATA_PARAMETERS); + + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/ClientLoansData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/ClientLoansData.java new file mode 100644 index 000000000..7abebaba9 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/ClientLoansData.java @@ -0,0 +1,47 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.portfolio.collectionsheet.data; + +import java.util.Collection; + +/** + * Immutable data object for clients with loans due for disbursement or collection. + */ +public class ClientLoansData { + + private final Long clientId; + private final String clientName; + private Collection loans; + + public ClientLoansData(final Long clientId, final String clientName, final Collection loans) { + this.clientId = clientId; + this.clientName = clientName; + this.loans = loans; + } + + public ClientLoansData(final Long clientId, final String clientName) { + this.clientId = clientId; + this.clientName = clientName; + this.loans = null; + } + + public Long getClientId() { + return this.clientId; + } + + public String getClientName() { + return this.clientName; + } + + public Collection getLoans() { + return this.loans; + } + + public void setLoans(final Collection loans) { + this.loans = loans; + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGClientsData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGClientsData.java new file mode 100644 index 000000000..1214007ee --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGClientsData.java @@ -0,0 +1,64 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.portfolio.collectionsheet.data; + +import java.util.Collection; + +/** + * Immutable data object for groups with clients due for disbursement or collection. + */ +public class JLGClientsData { + + private final Long groupId; + private final String groupName; + private final Long staffId; + private final String staffName; + private final Long levelId; + private final String levelName; + private Collection clients; + + public JLGClientsData(final Long groupId, final String groupName, final Long staffId, final String staffName, final Long levelId, + final String levelName) { + this.groupId = groupId; + this.groupName = groupName; + this.staffId = staffId; + this.staffName = staffName; + this.levelId = levelId; + this.levelName = levelName; + } + + public Long getGroupId() { + return this.groupId; + } + + public String getGroupName() { + return this.groupName; + } + + public Long getStaffId() { + return this.staffId; + } + + public String getStaffName() { + return this.staffName; + } + + public Long getLevelId() { + return this.levelId; + } + + public String getLevelName() { + return this.levelName; + } + + public Collection getCutomers() { + return this.clients; + } + + public void setClients(final Collection clients) { + this.clients = clients; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGCollectionSheetData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGCollectionSheetData.java new file mode 100644 index 000000000..e37c24d62 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGCollectionSheetData.java @@ -0,0 +1,33 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.portfolio.collectionsheet.data; + +import java.util.Collection; + +import org.joda.time.LocalDate; + +/** + * Immutable data object for join liability group's collection sheet. + */ +public class JLGCollectionSheetData { + + private final LocalDate dueDate; + private final Collection groups; + + public JLGCollectionSheetData(final LocalDate date, final Collection groups) { + this.dueDate = date; + this.groups = groups; + } + + public LocalDate getDate() { + return this.dueDate; + } + + public Collection getGroups() { + return this.groups; + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGCollectionSheetFlatData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGCollectionSheetFlatData.java new file mode 100644 index 000000000..69859f46c --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGCollectionSheetFlatData.java @@ -0,0 +1,164 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.portfolio.collectionsheet.data; + +import java.math.BigDecimal; + +/** + * Immutable data object for extracting flat data for joint liability group's collection sheet. + */ +public class JLGCollectionSheetFlatData { + + private final String groupName; + private final Long groupId; + private final Long staffId; + private final String staffName; + private final Long levelId; + private final String levelName; + private final String clientName; + private final Long clientId; + private final Long loanId; + private final String accountId; + private final Integer accountStatusId; + private final String productShortName; + private final Long productId; + private final String currencyCode; + private final Integer currencyDigits; + private BigDecimal disbursementAmount = BigDecimal.ZERO; + private BigDecimal principalDue = BigDecimal.ZERO; + private BigDecimal principalPaid = BigDecimal.ZERO; + private BigDecimal interestDue = BigDecimal.ZERO; + private BigDecimal interestPaid = BigDecimal.ZERO; + private BigDecimal chargesDue = BigDecimal.ZERO; + + public JLGCollectionSheetFlatData(final String groupName, final Long groupId, final Long staffId, final String staffName, + final Long levelId, final String levelName, final String clientName, final Long clientId, final Long loanId, + final String accountId, final Integer accountStatusId, final String productShortName, final Long productId, + final String currencyCode, final Integer currencyDigits, final BigDecimal disbursementAmount, final BigDecimal principalDue, + final BigDecimal principalPaid, final BigDecimal interestDue, final BigDecimal interestPaid, final BigDecimal chargesDue) { + this.groupName = groupName; + this.groupId = groupId; + this.staffId = staffId; + this.staffName = staffName; + this.levelId = levelId; + this.levelName = levelName; + this.clientName = clientName; + this.clientId = clientId; + this.loanId = loanId; + this.accountId = accountId; + this.accountStatusId = accountStatusId; + this.productShortName = productShortName; + this.productId = productId; + this.currencyCode = currencyCode; + this.currencyDigits = currencyDigits; + this.disbursementAmount = disbursementAmount; + this.principalDue = principalDue; + this.principalPaid = principalPaid; + this.interestDue = interestDue; + this.interestPaid = interestPaid; + this.chargesDue = chargesDue; + } + + public String getGroupName() { + return this.groupName; + } + + public Long getGroupId() { + return this.groupId; + } + + public Long getStaffId() { + return this.staffId; + } + + public String getStaffName() { + return this.staffName; + } + + public Long getLevelId() { + return this.levelId; + } + + public String getLevelName() { + return this.levelName; + } + + public String getClientName() { + return this.clientName; + } + + public Long getClientId() { + return this.clientId; + } + + public Long getLoanId() { + return this.loanId; + } + + public String getAccountId() { + return this.accountId; + } + + public Integer getAccountStatusId() { + return this.accountStatusId; + } + + public String getProductShortName() { + return this.productShortName; + } + + public Long getProductId() { + return this.productId; + } + + public String getCurrencyCode() { + return this.currencyCode; + } + + public Integer getCurrencyDigits() { + return this.currencyDigits; + } + + public BigDecimal getDisbursementAmount() { + return this.disbursementAmount; + } + + public BigDecimal getPrincipalDue() { + return this.principalDue; + } + + public BigDecimal getPrincipalPaid() { + return this.principalPaid; + } + + public BigDecimal getInterestDue() { + return this.interestDue; + } + + public BigDecimal getInterestPaid() { + return this.interestPaid; + } + + public BigDecimal getChargesDue() { + return this.chargesDue; + } + + public LoanDueData getLoanDueData() { + return new LoanDueData(this.loanId, this.accountId, this.accountStatusId, this.productShortName, this.productId, this.currencyCode, + this.currencyDigits, this.disbursementAmount, this.principalDue, this.principalPaid, this.interestDue, this.interestPaid, + this.chargesDue); + } + + public ClientLoansData getClientLoansData() { + return new ClientLoansData(this.clientId, this.clientName); + } + + public JLGClientsData getJLGClientsData() { + + return new JLGClientsData(this.groupId, this.groupName, this.staffId, this.staffName, this.levelId, this.levelName); + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/LoanDueData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/LoanDueData.java new file mode 100644 index 000000000..5d598e014 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/LoanDueData.java @@ -0,0 +1,100 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.portfolio.collectionsheet.data; + +import java.math.BigDecimal; + +/** + * Immutable data object for representing loan with dues (example: loan is due for disbursement, repayments). + */ +public class LoanDueData { + + private final Long loanId; + private final String accountId; + private final Integer accountStatusId; + private final String productShortName; + private final Long productId; + private final String currencyCode; + private final Integer currencyDigits; + private BigDecimal disbursementAmount = BigDecimal.ZERO; + private BigDecimal principalDue = BigDecimal.ZERO; + private BigDecimal principalPaid = BigDecimal.ZERO; + private BigDecimal interestDue = BigDecimal.ZERO; + private BigDecimal interestPaid = BigDecimal.ZERO; + private BigDecimal chargesDue = BigDecimal.ZERO; + + public LoanDueData(final Long loanId, final String accountId, final Integer accountStatusId, final String productShortName, + final Long productId, final String currencyCode, final Integer currencyDigits, final BigDecimal disbursementAmount, + final BigDecimal principalDue, final BigDecimal principalPaid, final BigDecimal interestDue, final BigDecimal interestPaid, + final BigDecimal chargesDue) { + this.loanId = loanId; + this.accountId = accountId; + this.accountStatusId = accountStatusId; + this.productShortName = productShortName; + this.productId = productId; + this.currencyCode = currencyCode; + this.currencyDigits = currencyDigits; + this.disbursementAmount = disbursementAmount; + this.principalDue = principalDue; + this.principalPaid = principalPaid; + this.interestDue = interestDue; + this.interestPaid = interestPaid; + this.chargesDue = chargesDue; + } + + public Long getLoanId() { + return this.loanId; + } + + public String getAccountId() { + return this.accountId; + } + + public Integer getAccountStatusId() { + return this.accountStatusId; + } + + public String getProductShortName() { + return this.productShortName; + } + + public Long getProductId() { + return this.productId; + } + + public String getCurrencyCode() { + return this.currencyCode; + } + + public Integer getCurrencyDigits() { + return this.currencyDigits; + } + + public BigDecimal getDisbursementAmount() { + return this.disbursementAmount; + } + + public BigDecimal getPrincipalDue() { + return this.principalDue; + } + + public BigDecimal getPrincipalPaid() { + return this.principalPaid; + } + + public BigDecimal getInterestDue() { + return this.interestDue; + } + + public BigDecimal getInterestPaid() { + return this.interestPaid; + } + + public BigDecimal getChargesDue() { + return this.chargesDue; + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/service/CollectionSheetReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/service/CollectionSheetReadPlatformService.java new file mode 100644 index 000000000..238f4c576 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/service/CollectionSheetReadPlatformService.java @@ -0,0 +1,15 @@ +package org.mifosplatform.portfolio.collectionsheet.service; + +import java.util.Collection; + +import org.joda.time.LocalDate; +import org.mifosplatform.portfolio.collectionsheet.data.JLGCollectionSheetData; +import org.mifosplatform.portfolio.collectionsheet.data.JLGCollectionSheetFlatData; + +public interface CollectionSheetReadPlatformService { + + JLGCollectionSheetData retriveCollectionSheet(LocalDate localDate, Long groupId); + + Collection retriveJLGCollectionSheet(String groupHierarchy, String officeHierarchy, LocalDate dueDate); + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/service/CollectionSheetReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/service/CollectionSheetReadPlatformServiceImpl.java new file mode 100644 index 000000000..9477c6da0 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/service/CollectionSheetReadPlatformServiceImpl.java @@ -0,0 +1,239 @@ +package org.mifosplatform.portfolio.collectionsheet.service; + +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.domain.JdbcSupport; +import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.mifosplatform.portfolio.collectionsheet.data.ClientLoansData; +import org.mifosplatform.portfolio.collectionsheet.data.JLGClientsData; +import org.mifosplatform.portfolio.collectionsheet.data.JLGCollectionSheetData; +import org.mifosplatform.portfolio.collectionsheet.data.JLGCollectionSheetFlatData; +import org.mifosplatform.portfolio.collectionsheet.data.LoanDueData; +import org.mifosplatform.portfolio.group.data.GroupData; +import org.mifosplatform.portfolio.group.exception.GroupNotFoundException; +import org.mifosplatform.portfolio.group.service.GroupReadPlatformServiceImpl; +import org.mifosplatform.useradministration.domain.AppUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.jdbc.core.namedparam.SqlParameterSource; +import org.springframework.stereotype.Service; + +@Service +public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetReadPlatformService { + + private final PlatformSecurityContext context; + private final NamedParameterJdbcTemplate namedParameterjdbcTemplate; + private final GroupReadPlatformServiceImpl groupReadPlatformServiceImpl; + + @Autowired + public CollectionSheetReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource, + final GroupReadPlatformServiceImpl groupReadPlatformServiceImpl) { + this.context = context; + this.namedParameterjdbcTemplate = new NamedParameterJdbcTemplate(dataSource); + this.groupReadPlatformServiceImpl = groupReadPlatformServiceImpl; + } + + @Override + public JLGCollectionSheetData retriveCollectionSheet(final LocalDate dueDate, final Long groupId) { + + final AppUser currentUser = this.context.authenticatedUser(); + final String hierarchy = currentUser.getOffice().getHierarchy(); + final String officeHierarchy = hierarchy + "%"; + + final GroupData groupData = this.groupReadPlatformServiceImpl.retrieveGroup(groupId); + if (groupData == null) { throw new GroupNotFoundException(groupId); } + + final String groupHierarchy = groupData.getHierarchy() + "%"; + + final JLGCollectionSheetData jlgCollectionSheetData = buildJLGCollectionSheet(groupHierarchy, officeHierarchy, dueDate); + + return jlgCollectionSheetData; + } + + /** + * @param groupHierarchy + * @param officeHierarchy + * @param dueDate + * @return + * + * Reads all the loans which are due for disbursement or collection + * and builds hierarchical data structure for collections sheet with + * hierarchy Groups >> Clients >> Loans. + * + */ + @SuppressWarnings("null") + private JLGCollectionSheetData buildJLGCollectionSheet(final String groupHierarchy, final String officeHierarchy, + final LocalDate dueDate) { + + final Collection jlgCollectionSheetFlatData = retriveJLGCollectionSheet(groupHierarchy, + officeHierarchy, dueDate); + + boolean firstTime = true; + Long prevGroupId = null; + Long prevClientId = null; + + final List jlgClientsDatas = new ArrayList(); + List clientLoansDatas = new ArrayList(); + List loanDueDatas = new ArrayList(); + + JLGCollectionSheetData jlgCollectionSheetData = null; + JLGCollectionSheetFlatData prevCollectioSheetFlatData = null; + JLGCollectionSheetFlatData corrCollectioSheetFlatData = null; + + if (jlgCollectionSheetFlatData != null) { + + for (final JLGCollectionSheetFlatData collectionSheetFlatData : jlgCollectionSheetFlatData) { + + corrCollectioSheetFlatData = collectionSheetFlatData; + + if (firstTime || collectionSheetFlatData.getGroupId().equals(prevGroupId)) { + if (firstTime || collectionSheetFlatData.getClientId().equals(prevClientId)) { + if (collectionSheetFlatData.getLoanId() != null) { + loanDueDatas.add(collectionSheetFlatData.getLoanDueData()); + } + } else { + final ClientLoansData clientLoansData = prevCollectioSheetFlatData.getClientLoansData(); + clientLoansData.setLoans(loanDueDatas); + clientLoansDatas.add(clientLoansData); + loanDueDatas = new ArrayList(); + + if (collectionSheetFlatData.getLoanId() != null) { + loanDueDatas.add(collectionSheetFlatData.getLoanDueData()); + } + + } + } else { + + final ClientLoansData clientLoansData = prevCollectioSheetFlatData.getClientLoansData(); + clientLoansData.setLoans(loanDueDatas); + clientLoansDatas.add(clientLoansData); + + final JLGClientsData jlgClientsData = prevCollectioSheetFlatData.getJLGClientsData(); + jlgClientsData.setClients(clientLoansDatas); + + jlgClientsDatas.add(jlgClientsData); + + loanDueDatas = new ArrayList(); + clientLoansDatas = new ArrayList(); + + if (collectionSheetFlatData.getLoanId() != null) { + loanDueDatas.add(collectionSheetFlatData.getLoanDueData()); + } + } + + prevClientId = collectionSheetFlatData.getClientId(); + prevGroupId = collectionSheetFlatData.getGroupId(); + prevCollectioSheetFlatData = collectionSheetFlatData; + firstTime = false; + } + + // FIXME Need to check last loan is added under previous + // client/group or new client / previous group or new client / new + // group + + final ClientLoansData lastClientLoansData = corrCollectioSheetFlatData.getClientLoansData(); + lastClientLoansData.setLoans(loanDueDatas); + clientLoansDatas.add(lastClientLoansData); + + final JLGClientsData jlgClientsData = corrCollectioSheetFlatData.getJLGClientsData(); + jlgClientsData.setClients(clientLoansDatas); + + jlgClientsDatas.add(jlgClientsData); + + jlgCollectionSheetData = new JLGCollectionSheetData(dueDate, jlgClientsDatas); + } + + return jlgCollectionSheetData; + } + + @Override + public Collection retriveJLGCollectionSheet(final String groupHierarchy, final String officeHierarchy, + final LocalDate dueDate) { + + final JLGCollectionSheetFaltDataMapper mapper = new JLGCollectionSheetFaltDataMapper(); + final String sql = mapper.collectionSheetSchema(); + + final SqlParameterSource namedParameters = new MapSqlParameterSource().addValue("hierarchy", groupHierarchy) + .addValue("dueDate", dueDate).addValue("officeHierarchy", officeHierarchy); + return this.namedParameterjdbcTemplate.query(sql, namedParameters, mapper); + } + + private static final class JLGCollectionSheetFaltDataMapper implements RowMapper { + + public String collectionSheetSchema() { + + return "SELECT gp.name As groupName, " + + "gp.id As groupId, " + + "cl.display_name As clientName, " + + "sf.id As staffId, " + + "sf.display_name As staffName, " + + "gl.id As levelId, " + + "gl.level_name As levelName, " + + "cl.id As clientId, " + + "ln.id As loanId, " + + "ln.account_no As accountId, " + + "ln.loan_status_id As accountStatusId, " + + "pl.name As productShortName, " + + "ln.product_id As productId, " + + "ln.currency_code As currencyCode, " + + "ln.currency_digits As currencyDigits, " + + "if(ln.loan_status_id = 200 , ln.principal_amount , null) As disbursementAmount, " + + "sum(ls.principal_amount - ls.principal_completed_derived) As principalDue, " + + "ln.principal_repaid_derived As principalPaid, " + + "sum(ls.interest_amount - ls.interest_completed_derived) As interestDue, " + + "ln.interest_repaid_derived As interestPaid, " + + "sum(lc.amount_outstanding_derived) as chargesDue " + + "FROM m_group gp " + + "LEFT JOIN m_office of ON of.id = gp.office_id AND of.hierarchy like :officeHierarchy " + + "JOIN m_group_level gl ON gl.id = gp.level_Id " + + "LEFT JOIN m_staff sf ON sf.id = gp.staff_id " + + "JOIN m_group_client gc ON gc.group_id = gp.id " + + "JOIN m_client cl ON cl.id = gc.client_id " + + "LEFT JOIN m_loan ln ON cl.id = ln.client_id AND ln.group_id is not null AND ( ln.loan_status_id = 300 OR ( ln.loan_status_id =200 AND ln.expected_disbursedon_date <= :dueDate )) " + + "LEFT JOIN m_product_loan pl ON pl.id = ln.product_id " + + "LEFT JOIN m_loan_repayment_schedule ls ON ls.loan_id = ln.id AND ls.completed_derived = 0 AND ls.duedate <= :dueDate " + + "LEFT JOIN m_loan_charge lc ON lc.loan_id = ln.id AND lc.is_paid_derived = 0 AND ( lc.due_for_collection_as_of_date <= :dueDate OR lc.charge_time_enum = 1) " + + "WHERE gp.hierarchy like :hierarchy " + "GROUP BY gp.id ,cl.id , ln.id " + "ORDER BY gp.id , cl.id , ln.id "; + } + + @Override + public JLGCollectionSheetFlatData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + final String groupName = rs.getString("groupName"); + final Long groupId = JdbcSupport.getLong(rs, "groupId"); + final Long staffId = JdbcSupport.getLong(rs, "staffId"); + final String staffName = rs.getString("staffName"); + final Long levelId = JdbcSupport.getLong(rs, "levelId"); + final String levelName = rs.getString("levelName"); + final String clientName = rs.getString("clientName"); + final Long clientId = JdbcSupport.getLong(rs, "clientId"); + final Long loanId = JdbcSupport.getLong(rs, "loanId"); + final String accountId = rs.getString("accountId"); + final Integer accountStatusId = JdbcSupport.getInteger(rs, "accountStatusId"); + final String productShortName = rs.getString("productShortName"); + final Long productId = JdbcSupport.getLong(rs, "productId"); + final String currencyCode = rs.getString("currencyCode"); + final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits"); + final BigDecimal disbursementAmount = rs.getBigDecimal("disbursementAmount"); + final BigDecimal principalDue = rs.getBigDecimal("principalDue"); + final BigDecimal principalPaid = rs.getBigDecimal("principalPaid"); + final BigDecimal interestDue = rs.getBigDecimal("interestDue"); + final BigDecimal interestPaid = rs.getBigDecimal("interestPaid"); + final BigDecimal chargesDue = rs.getBigDecimal("chargesDue"); + + return new JLGCollectionSheetFlatData(groupName, groupId, staffId, staffName, levelId, levelName, clientName, clientId, loanId, + accountId, accountStatusId, productShortName, productId, currencyCode, currencyDigits, disbursementAmount, + principalDue, principalPaid, interestDue, interestPaid, chargesDue); + } + + } +}