GLIM_GSIM enhancement (FINERACT-603)

This commit is contained in:
rrpawar96
2020-05-05 12:43:40 +02:00
committed by Michael Vorburger ⛑️
parent edfcb931e9
commit 489faf96b0
95 changed files with 5067 additions and 227 deletions
@@ -883,6 +883,15 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder rejectGLIMApplication(final Long glimId) {
this.actionName = "REJECT";
this.entityName = "GLIMLOAN";
this.entityId = glimId;
this.loanId = glimId;
this.href = "/loans/" + glimId;
return this;
}
public CommandWrapperBuilder withdrawLoanApplication(final Long loanId) {
this.actionName = "WITHDRAW";
this.entityName = "LOAN";
@@ -901,6 +910,50 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder approveGLIMLoanApplication(final Long glimId) {
this.actionName = "APPROVE";
this.entityName = "GLIMLOAN";
this.entityId = glimId;
this.loanId = glimId;
this.href = "/loans/" + glimId;
return this;
}
public CommandWrapperBuilder disburseGlimLoanApplication(final Long glimId) {
this.actionName = "DISBURSE";
this.entityName = "GLIMLOAN";
this.entityId = glimId;
this.loanId = glimId;
this.href = "/loans/" + glimId;
return this;
}
public CommandWrapperBuilder repaymentGlimLoanApplication(final Long glimId) {
this.actionName = "REPAYMENT";
this.entityName = "GLIMLOAN";
this.entityId = glimId;
this.loanId = glimId;
this.href = "/loans/" + glimId;
return this;
}
public CommandWrapperBuilder undoGLIMLoanDisbursal(final Long glimId) {
this.actionName = "UNDODISBURSAL";
this.entityName = "GLIMLOAN";
this.entityId = glimId;
this.loanId = glimId;
this.href = "/loans/" + glimId;
return this;
}
public CommandWrapperBuilder undoGLIMLoanApproval(final Long glimId) {
this.actionName = "UNDOAPPROVAL";
this.entityName = "GLIMLOAN";
this.entityId = glimId;
this.loanId = glimId;
this.href = "/loans/" + glimId;
return this;
}
public CommandWrapperBuilder disburseLoanApplication(final Long loanId) {
this.actionName = "DISBURSE";
this.entityName = "LOAN";
@@ -1126,6 +1179,14 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder createGSIMAccount() {
this.actionName = "CREATE";
this.entityName = "GSIMACCOUNT";
this.entityId = null;
this.href = "/gsimaccounts/template";
return this;
}
public CommandWrapperBuilder updateSavingsAccount(final Long accountId) {
this.actionName = "UPDATE";
this.entityName = "SAVINGSACCOUNT";
@@ -1134,6 +1195,14 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder updateGSIMAccount(final Long accountId) {
this.actionName = "UPDATE";
this.entityName = "GSIMACCOUNT";
this.entityId = accountId;
this.href = "/gsimaccounts/" + accountId;
return this;
}
public CommandWrapperBuilder deleteSavingsAccount(final Long accountId) {
this.actionName = "DELETE";
this.entityName = "SAVINGSACCOUNT";
@@ -1151,6 +1220,15 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder rejectGSIMAccountApplication(final Long accountId) {
this.actionName = "REJECT";
this.entityName = "GSIMACCOUNT";
this.entityId = accountId;
this.savingsId = accountId;
this.href = "/savingsaccounts/" + accountId + "?command=reject";
return this;
}
public CommandWrapperBuilder withdrawSavingsAccountApplication(final Long accountId) {
this.actionName = "WITHDRAW";
this.entityName = "SAVINGSACCOUNT";
@@ -1169,6 +1247,15 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder approveGSIMAccountApplication(final Long accountId) {
this.actionName = "APPROVE";
this.entityName = "GSIMACCOUNT";
this.entityId = accountId;
this.savingsId = accountId;
this.href = "/gsimsaccounts/" + accountId + "?command=approve";
return this;
}
public CommandWrapperBuilder undoSavingsAccountApplication(final Long accountId) {
this.actionName = "APPROVALUNDO";
this.entityName = "SAVINGSACCOUNT";
@@ -1178,6 +1265,15 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder undoGSIMApplicationApproval(final Long accountId) {
this.actionName = "APPROVALUNDO";
this.entityName = "GSIMACCOUNT";
this.entityId = accountId;
this.savingsId = accountId;
this.href = "/savingsaccounts/" + accountId + "?command=undoapproval";
return this;
}
public CommandWrapperBuilder savingsAccountActivation(final Long accountId) {
this.actionName = "ACTIVATE";
this.entityName = "SAVINGSACCOUNT";
@@ -1187,6 +1283,15 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder gsimAccountActivation(final Long accountId) {
this.actionName = "ACTIVATE";
this.entityName = "GSIMACCOUNT";
this.savingsId = accountId;
this.entityId = null;
this.href = "/savingsaccounts/" + accountId + "?command=activate";
return this;
}
public CommandWrapperBuilder closeSavingsAccountApplication(final Long accountId) {
this.actionName = "CLOSE";
this.entityName = "SAVINGSACCOUNT";
@@ -1196,6 +1301,15 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder closeGSIMApplication(final Long accountId) {
this.actionName = "CLOSE";
this.entityName = "GSIMACCOUNT";
this.entityId = accountId;
this.savingsId = accountId;
this.href = "/savingsaccounts/" + accountId + "?command=close";
return this;
}
public CommandWrapperBuilder createAccountTransfer() {
this.actionName = "CREATE";
this.entityName = "ACCOUNTTRANSFER";
@@ -1237,6 +1351,15 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder gsimSavingsAccountDeposit(final Long accountId) {
this.actionName = "DEPOSIT";
this.entityName = "GSIMACCOUNT";
this.savingsId = accountId;
this.entityId = null;
this.href = "/savingsaccounts/" + accountId + "/transactions";
return this;
}
public CommandWrapperBuilder savingsAccountWithdrawal(final Long accountId) {
this.actionName = "WITHDRAWAL";
this.entityName = "SAVINGSACCOUNT";
@@ -97,6 +97,13 @@ public final class JsonCommand {
command.transactionId, command.url, command.productId,command.creditBureauId,command.organisationCreditBureauId);
}
public static JsonCommand fromExistingCommand(JsonCommand command, final JsonElement parsedCommand,final Long clientId) {
final String jsonCommand = command.fromApiJsonHelper.toJson(parsedCommand);
return new JsonCommand(command.commandId, jsonCommand, parsedCommand, command.fromApiJsonHelper, command.entityName,
command.resourceId, command.subresourceId, command.groupId, clientId, command.loanId, command.savingsId,
command.transactionId, command.url, command.productId,command.creditBureauId,command.organisationCreditBureauId);
}
public JsonCommand(final Long commandId, final String jsonCommand, final JsonElement parsedCommand,
final FromJsonHelper fromApiJsonHelper, final String entityName, final Long resourceId, final Long subresourceId,
final Long groupId, final Long clientId, final Long loanId, final Long savingsId, final String transactionId, final String url,
@@ -41,13 +41,15 @@ public class CommandProcessingResult implements Serializable {
@SuppressWarnings("unused")
private final String resourceIdentifier;
private final Long productId;
private final Long gsimId;
private final Long glimId;
private Boolean rollbackTransaction;
public static CommandProcessingResult fromDetails(final Long commandId, final Long officeId, final Long groupId, final Long clientId,
final Long loanId, final Long savingsId, final String resourceIdentifier, final Long entityId, final String transactionId,
final Long loanId, final Long savingsId, final String resourceIdentifier, final Long entityId, final Long gsimId, final Long glimId, final String transactionId,
final Map<String, Object> changes, final Long productId, final Boolean rollbackTransaction, final Long subResourceId) {
return new CommandProcessingResult(commandId, officeId, groupId, clientId, loanId, savingsId, resourceIdentifier, entityId,
transactionId, changes, productId, rollbackTransaction, subResourceId);
transactionId, changes, productId, gsimId, glimId, rollbackTransaction, subResourceId);
}
public static CommandProcessingResult commandOnlyResult(final Long commandId) {
@@ -97,12 +99,14 @@ public class CommandProcessingResult implements Serializable {
this.transactionId = null;
this.changes = new HashMap<>();
this.productId = null;
this.gsimId=null;
this.glimId=null;
this.subResourceId = null;
}
private CommandProcessingResult(final Long commandId, final Long officeId, final Long groupId, final Long clientId, final Long loanId,
final Long savingsId, final String resourceIdentifier, final Long resourceId, final String transactionId,
final Map<String, Object> changesOnly, final Long productId, Boolean rollbackTransaction, final Long subResourceId) {
final Map<String, Object> changesOnly, final Long productId, final Long gsimId, final Long glimId, Boolean rollbackTransaction, final Long subResourceId) {
this.commandId = commandId;
this.officeId = officeId;
this.groupId = groupId;
@@ -114,6 +118,8 @@ public class CommandProcessingResult implements Serializable {
this.changes = changesOnly;
this.transactionId = transactionId;
this.productId = productId;
this.gsimId=gsimId;
this.glimId=glimId;
this.rollbackTransaction = rollbackTransaction;
this.subResourceId = subResourceId;
}
@@ -134,6 +140,8 @@ public class CommandProcessingResult implements Serializable {
this.commandId = commandId;
this.changes = changesOnly;
this.productId = null;
this.gsimId=null;
this.glimId=null;
this.subResourceId = null;
}
@@ -190,6 +198,14 @@ public class CommandProcessingResult implements Serializable {
return this.productId;
}
public Long getGsimId() {
return this.gsimId;
}
public Long getGlimId() {
return this.glimId;
}
public boolean isRollbackTransaction() {
return this.rollbackTransaction != null && this.rollbackTransaction;
}
@@ -35,6 +35,8 @@ public class CommandProcessingResultBuilder {
private String resourceIdentifier;
private Long entityId;
private Long subEntityId;
private Long gsimId;
private Long glimId;
private String transactionId;
private Map<String, Object> changes;
private Long productId;
@@ -42,7 +44,7 @@ public class CommandProcessingResultBuilder {
public CommandProcessingResult build() {
return CommandProcessingResult.fromDetails(this.commandId, this.officeId, this.groupId, this.clientId, this.loanId, this.savingsId,
this.resourceIdentifier, this.entityId, this.transactionId, this.changes, this.productId, this.rollbackTransaction,
this.resourceIdentifier, this.entityId, this.gsimId, this.glimId, this.transactionId, this.changes, this.productId, this.rollbackTransaction,
this.subEntityId);
}
@@ -106,6 +108,16 @@ public class CommandProcessingResultBuilder {
return this;
}
public CommandProcessingResultBuilder withGsimId(final Long gsimId) {
this.gsimId = gsimId;
return this;
}
public CommandProcessingResultBuilder withGlimId(final Long glimId) {
this.glimId = glimId;
return this;
}
public CommandProcessingResultBuilder setRollbackTransaction(final boolean rollbackTransaction) {
this.rollbackTransaction = this.rollbackTransaction || rollbackTransaction;
return this;
@@ -52,6 +52,8 @@ import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
import org.apache.fineract.portfolio.savings.SavingsTransactionBooleanValues;
import org.apache.fineract.portfolio.savings.domain.GSIMRepositoy;
import org.apache.fineract.portfolio.savings.domain.GroupSavingsIndividualMonitoring;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountDomainService;
@@ -77,6 +79,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
private final SavingsAccountWritePlatformService savingsAccountWritePlatformService;
private final AccountTransferDetailRepository accountTransferDetailRepository;
private final LoanReadPlatformService loanReadPlatformService;
private final GSIMRepositoy gsimRepository;
@Autowired
public AccountTransfersWritePlatformServiceImpl(final AccountTransfersDataValidator accountTransfersDataValidator,
@@ -85,7 +88,8 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
final LoanAssembler loanAssembler, final LoanAccountDomainService loanAccountDomainService,
final SavingsAccountWritePlatformService savingsAccountWritePlatformService,
final AccountTransferDetailRepository accountTransferDetailRepository,
final LoanReadPlatformService loanReadPlatformService) {
final LoanReadPlatformService loanReadPlatformService,
final GSIMRepositoy gsimRepository) {
this.accountTransfersDataValidator = accountTransfersDataValidator;
this.accountTransferAssembler = accountTransferAssembler;
this.accountTransferRepository = accountTransferRepository;
@@ -96,6 +100,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
this.savingsAccountWritePlatformService = savingsAccountWritePlatformService;
this.accountTransferDetailRepository = accountTransferDetailRepository;
this.loanReadPlatformService = loanReadPlatformService;
this.gsimRepository=gsimRepository;
}
@Transactional
@@ -410,6 +415,16 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
toSavingsAccount, deposit, loanTransaction);
this.accountTransferDetailRepository.saveAndFlush(accountTransferDetails);
transferTransactionId = accountTransferDetails.getId();
// if the savings account is GSIM, update its parent as well
if(toSavingsAccount.getGsim()!=null)
{
GroupSavingsIndividualMonitoring gsim=gsimRepository.findById(toSavingsAccount.getGsim().getId()).get();
BigDecimal currentBalance=gsim.getParentDeposit();
BigDecimal newBalance=currentBalance.add(accountTransferDTO.getTransactionAmount());
gsim.setParentDeposit(newBalance);
gsimRepository.save(gsim);
}
} else {
throw new GeneralPlatformDomainRuleException("error.msg.accounttransfer.loan.to.loan.not.supported",
"Account transfer from loan to another loan is not supported");
@@ -27,6 +27,7 @@ import java.util.Collection;
public class AccountSummaryCollectionData {
private final Collection<LoanAccountSummaryData> loanAccounts;
private final Collection<LoanAccountSummaryData> groupLoanIndividualMonitoringAccounts;
private final Collection<SavingsAccountSummaryData> savingsAccounts;
private final Collection<ShareAccountSummaryData> shareAccounts ;
private final Collection<GuarantorAccountSummaryData> guarantorAccounts;
@@ -35,10 +36,15 @@ public class AccountSummaryCollectionData {
private final Collection<SavingsAccountSummaryData> memberSavingsAccounts;
private final Collection<GuarantorAccountSummaryData> memberGuarantorAccounts;
public AccountSummaryCollectionData(final Collection<LoanAccountSummaryData> loanAccounts,
final Collection<SavingsAccountSummaryData> savingsAccounts, final Collection<ShareAccountSummaryData> shareAccounts,
final Collection<GuarantorAccountSummaryData> guarantorAccounts) {
/* METHOD SIGNATURE CHANGE NOTICE: Method's signature
was changed for GLIM & GSIM implementation*/
public AccountSummaryCollectionData(final Collection<LoanAccountSummaryData> loanAccounts,final Collection<LoanAccountSummaryData> groupLoanIndividualMonitoringAccounts,
final Collection<SavingsAccountSummaryData> savingsAccounts, final Collection<ShareAccountSummaryData> shareAccounts,final Collection<GuarantorAccountSummaryData> guarantorAccounts)
{
this.loanAccounts = defaultLoanAccountsIfEmpty(loanAccounts);
this.groupLoanIndividualMonitoringAccounts=groupLoanIndividualMonitoringAccounts;
this.savingsAccounts = defaultSavingsAccountsIfEmpty(savingsAccounts);
this.shareAccounts = defaultShareAccountsIfEmpty(shareAccounts) ;
this.guarantorAccounts = guarantorAccounts;
@@ -47,10 +53,13 @@ public class AccountSummaryCollectionData {
this.memberGuarantorAccounts = null;
}
public AccountSummaryCollectionData(final Collection<LoanAccountSummaryData> loanAccounts,
public AccountSummaryCollectionData(final Collection<LoanAccountSummaryData> loanAccounts,final Collection<LoanAccountSummaryData> groupLoanIndividualMonitoringAccounts,
final Collection<SavingsAccountSummaryData> savingsAccounts, final Collection<GuarantorAccountSummaryData> guarantorAccounts, final Collection<LoanAccountSummaryData> memberLoanAccounts,
final Collection<SavingsAccountSummaryData> memberSavingsAccounts, final Collection<GuarantorAccountSummaryData> memberGuarantorAccounts) {
/* Note to Self: GSIM not passed in*/
this.loanAccounts = defaultLoanAccountsIfEmpty(loanAccounts);
this.groupLoanIndividualMonitoringAccounts=groupLoanIndividualMonitoringAccounts;
this.savingsAccounts = defaultSavingsAccountsIfEmpty(savingsAccounts);
this.guarantorAccounts = guarantorAccounts;
this.shareAccounts = null ;
@@ -31,6 +31,7 @@ public class LoanAccountSummaryData {
private final Long id;
private final String accountNo;
private final String parentAccountNumber;
private final String externalId;
private final Long productId;
private final String productName;
@@ -49,6 +50,28 @@ public class LoanAccountSummaryData {
final LoanApplicationTimelineData timeline, final Boolean inArrears,final BigDecimal originalLoan,final BigDecimal loanBalance,final BigDecimal amountPaid) {
this.id = id;
this.accountNo = accountNo;
this.parentAccountNumber=null;
this.externalId = externalId;
this.productId = productId;
this.productName = loanProductName;
this.shortProductName = shortLoanProductName;
this.status = loanStatus;
this.loanType = loanType;
this.loanCycle = loanCycle;
this.timeline = timeline;
this.inArrears = inArrears;
this.loanBalance = loanBalance;
this.originalLoan = originalLoan;
this.amountPaid = amountPaid;
}
public LoanAccountSummaryData(final Long id, final String accountNo,final String parentAccountNumber, final String externalId, final Long productId,
final String loanProductName, final String shortLoanProductName, final LoanStatusEnumData loanStatus, final EnumOptionData loanType, final Integer loanCycle,
final LoanApplicationTimelineData timeline, final Boolean inArrears,final BigDecimal originalLoan,final BigDecimal loanBalance,final BigDecimal amountPaid) {
this.id = id;
this.accountNo = accountNo;
this.parentAccountNumber=parentAccountNumber;
this.externalId = externalId;
this.productId = productId;
this.productName = loanProductName;
@@ -69,4 +69,12 @@ public class SavingsAccountSummaryData {
this.subStatus = subStatus;
this.lastActiveTransactionDate = lastActiveTransactionDate;
}
public String getAccountNo() {
return accountNo;
}
public Long getId() {
return id;
}
}
@@ -0,0 +1,83 @@
/**
* 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.accountdetails.data;
import java.math.BigDecimal;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountApplicationTimelineData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountStatusEnumData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountSubStatusEnumData;
import org.joda.time.LocalDate;
@SuppressWarnings("unused")
public class SavingsSummaryCustom
{
private final Long id;
private final String displayName;
private final String accountNo;
private final String externalId;
private final Long productId;
private final String productName;
private final String shortProductName;
private final SavingsAccountStatusEnumData status;
private final CurrencyData currency;
private final BigDecimal accountBalance;
//differentiate Individual, JLG or Group account
private final EnumOptionData accountType;
private final SavingsAccountApplicationTimelineData timeline;
private final SavingsAccountSubStatusEnumData subStatus;
private final LocalDate lastActiveTransactionDate;
//differentiate deposit accounts Savings, FD and RD accounts
private final EnumOptionData depositType;
public SavingsSummaryCustom(final Long id,final String displayName, final String accountNo, final String externalId, final Long productId,
final String productName, final String shortProductName, final SavingsAccountStatusEnumData status, final CurrencyData currency,
final BigDecimal accountBalance, final EnumOptionData accountType, final SavingsAccountApplicationTimelineData timeline, final EnumOptionData depositType,
final SavingsAccountSubStatusEnumData subStatus, final LocalDate lastActiveTransactionDate) {
this.id = id;
this.displayName=displayName;
this.accountNo = accountNo;
this.externalId = externalId;
this.productId = productId;
this.productName = productName;
this.shortProductName = shortProductName;
this.status = status;
this.currency = currency;
this.accountBalance = accountBalance;
this.accountType = accountType;
this.timeline = timeline;
this.depositType = depositType;
this.subStatus = subStatus;
this.lastActiveTransactionDate = lastActiveTransactionDate;
}
public String getAccountNo() {
return accountNo;
}
public Long getId() {
return id;
}
}
@@ -26,7 +26,9 @@ public enum AccountType {
INVALID(0, "accountType.invalid"), //
INDIVIDUAL(1, "accountType.individual"), //
GROUP(2, "accountType.group"), //
JLG(3, "accountType.jlg");// JLG account given in group context
JLG(3, "accountType.jlg"),// JLG account given in group context
GLIM(4, "accountType.glim"),
GSIM(5, "accountType.gsim");
private final Integer value;
private final String code;
@@ -49,6 +51,12 @@ public enum AccountType {
case 3:
enumeration = AccountType.JLG;
break;
case 4:
enumeration = AccountType.GLIM;
break;
case 5:
enumeration = AccountType.GSIM;
break;
}
return enumeration;
}
@@ -91,4 +99,12 @@ public enum AccountType {
public boolean isJLGAccount() {
return this.value.equals(AccountType.JLG.getValue());
}
public boolean isGLIMAccount() {
return this.value.equals(AccountType.GLIM.getValue());
}
public boolean isGSIMAccount() {
return this.value.equals(AccountType.GSIM.getValue());
}
}
@@ -19,6 +19,7 @@
package org.apache.fineract.portfolio.accountdetails.service;
import java.util.Collection;
import java.util.List;
import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData;
import org.apache.fineract.portfolio.accountdetails.data.LoanAccountSummaryData;
@@ -33,4 +34,8 @@ public interface AccountDetailsReadPlatformService {
public Collection<LoanAccountSummaryData> retrieveGroupLoanAccountsByLoanOfficerId(final Long groupId, final Long loanOfficerId);
public Collection<LoanAccountSummaryData> retrieveClientActiveLoanAccountSummary(final Long clientId);
public List<LoanAccountSummaryData> retrieveLoanAccountDetailsByGroupIdAndGlimAccountNumber(Long groupId,final String glimAccount);
AccountSummaryCollectionData retrieveGroupAccountDetails(Long groupId, Long gsimId);
}
@@ -74,15 +74,20 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
// Check if client exists
this.clientReadPlatformService.retrieveOne(clientId);
final String loanwhereClause = " where l.client_id = ?";
final String glimLoanClause=" where l.client_id = ? and l.loan_type_enum=4";
//note to self: investigate the effect of have loans stored as another type especially given that we want to maintain how the system currently handles loans of exisiting types.
final String savingswhereClause = " where sa.client_id = ? order by sa.status_enum ASC, sa.account_no ASC";
final String guarantorWhereClause = " where g.entity_id = ? and g.is_active = 1 order by l.account_no ASC";
final List<LoanAccountSummaryData> glimAccounts = retrieveLoanAccountDetails(glimLoanClause, new Object[] { clientId });
final List<LoanAccountSummaryData> loanAccounts = retrieveLoanAccountDetails(loanwhereClause, new Object[] { clientId });
final List<SavingsAccountSummaryData> savingsAccounts = retrieveAccountDetails(savingswhereClause, new Object[] { clientId });
final List<ShareAccountSummaryData> shareAccounts = retrieveShareAccountDetails(clientId) ;
final List<GuarantorAccountSummaryData> guarantorloanAccounts = retrieveGuarantorLoanAccountDetails(
guarantorWhereClause, new Object[] { clientId });
return new AccountSummaryCollectionData(loanAccounts, savingsAccounts, shareAccounts, guarantorloanAccounts);
guarantorWhereClause, new Object[] { clientId });
return new AccountSummaryCollectionData(loanAccounts,glimAccounts, savingsAccounts, shareAccounts,guarantorloanAccounts);
}
@Override
@@ -90,11 +95,14 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
// Check if group exists
this.groupReadPlatformService.retrieveOne(groupId);
final String loanWhereClauseForGroup = " where l.group_id = ? and l.client_id is null";
final String loanWhereClauseForGroupAndLoanType = " where l.group_id = ? and l.loan_type_enum=4";
final String loanWhereClauseForMembers = " where l.group_id = ? and l.client_id is not null";
final String savingswhereClauseForGroup = " where sa.group_id = ? and sa.client_id is null order by sa.status_enum ASC, sa.account_no ASC";
final String savingswhereClauseForMembers = " where sa.group_id = ? and sa.client_id is not null order by sa.status_enum ASC, sa.account_no ASC";
final String guarantorWhereClauseForGroup = " where l.group_id = ? and l.client_id is null and g.is_active = 1 order by l.account_no ASC";
final String guarantorWhereClauseForMembers = " where l.group_id = ? and l.client_id is not null and g.is_active = 1 order by l.account_no ASC";
final List<LoanAccountSummaryData> glimAccounts = retrieveLoanAccountDetails(loanWhereClauseForGroupAndLoanType, new Object[] { groupId });
final List<LoanAccountSummaryData> groupLoanAccounts = retrieveLoanAccountDetails(loanWhereClauseForGroup, new Object[] { groupId });
final List<SavingsAccountSummaryData> groupSavingsAccounts = retrieveAccountDetails(savingswhereClauseForGroup,
@@ -105,9 +113,32 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
new Object[] { groupId });
final List<SavingsAccountSummaryData> memberSavingsAccounts = retrieveAccountDetails(savingswhereClauseForMembers,
new Object[] { groupId });
final List<GuarantorAccountSummaryData> memberGuarantorloanAccounts = retrieveGuarantorLoanAccountDetails(
guarantorWhereClauseForMembers, new Object[] { groupId });
return new AccountSummaryCollectionData(groupLoanAccounts, groupSavingsAccounts, groupGuarantorloanAccounts, memberLoanAccounts, memberSavingsAccounts, memberGuarantorloanAccounts);
guarantorWhereClauseForMembers, new Object[] { groupId });
return new AccountSummaryCollectionData(groupLoanAccounts,glimAccounts, groupSavingsAccounts, groupGuarantorloanAccounts, memberLoanAccounts, memberSavingsAccounts, memberGuarantorloanAccounts);
}
@Override
public AccountSummaryCollectionData retrieveGroupAccountDetails(final Long groupId,final Long gsimId) {
// Check if group exists
this.groupReadPlatformService.retrieveOne(groupId);
final String loanWhereClauseForGroup = " where l.group_id = ? and l.client_id is null";
final String loanWhereClauseForGroupAndLoanType = " where l.group_id = ? and l.loan_type_enum=4";
final String loanWhereClauseForMembers = " where l.group_id = ? and l.client_id is not null";
final String savingswhereClauseForGroup = " where sa.group_id = ? and sa.gsim_id = ? sa.client_id is null order by sa.status_enum ASC, sa.account_no ASC";
final String savingswhereClauseForMembers = " where sa.group_id = ? and sa.client_id is not null order by sa.status_enum ASC, sa.account_no ASC";
final List<LoanAccountSummaryData> glimAccounts = retrieveLoanAccountDetails(loanWhereClauseForGroupAndLoanType, new Object[] { groupId });
final List<LoanAccountSummaryData> groupLoanAccounts = retrieveLoanAccountDetails(loanWhereClauseForGroup, new Object[] { groupId });
final List<SavingsAccountSummaryData> gsimSavingsAccounts = retrieveAccountDetails(savingswhereClauseForGroup,
new Object[] { groupId,gsimId });
final List<LoanAccountSummaryData> memberLoanAccounts = retrieveLoanAccountDetails(loanWhereClauseForMembers,
new Object[] { groupId });
final List<SavingsAccountSummaryData> memberSavingsAccounts = retrieveAccountDetails(savingswhereClauseForMembers,
new Object[] { groupId });
return new AccountSummaryCollectionData(groupLoanAccounts, glimAccounts,gsimSavingsAccounts, null,memberLoanAccounts, memberSavingsAccounts,null);
}
@Override
@@ -131,6 +162,16 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
return retrieveLoanAccountDetails(loanWhereClause, new Object[] { clientId });
}
@Override
public List<LoanAccountSummaryData> retrieveLoanAccountDetailsByGroupIdAndGlimAccountNumber(final Long groupId,final String glimAccount) {
final LoanAccountSummaryDataMapper rm = new LoanAccountSummaryDataMapper();
final String loanWhereClauseForGroupAndLoanType = " where l.group_id =? and glim.account_number=? and l.loan_type_enum=4";
final String sql = "select " + rm.loanAccountSummarySchema() + loanWhereClauseForGroupAndLoanType;
// this.columnValidator.validateSqlInjection(rm.loanAccountSummarySchema(), loanWhereClauseForGroupAndLoanType);
return this.jdbcTemplate.query(sql, rm, new Object[]{groupId , glimAccount});
}
private List<LoanAccountSummaryData> retrieveLoanAccountDetails(final String loanwhereClause, final Object[] inputs) {
final LoanAccountSummaryDataMapper rm = new LoanAccountSummaryDataMapper();
final String sql = "select " + rm.loanAccountSummarySchema() + loanwhereClause;
@@ -404,6 +445,8 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
.append(" l.product_id as productId, lp.name as productName, lp.short_name as shortProductName,")
.append(" l.loan_status_id as statusId, l.loan_type_enum as loanType,")
.append(" glim.account_number as parentAccountNumber,")
.append("l.principal_disbursed_derived as originalLoan,")
.append("l.total_outstanding_derived as loanBalance,")
.append("l.total_repayment_derived as amountPaid,")
@@ -437,7 +480,8 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
.append(" left join m_appuser abu on abu.id = l.approvedon_userid")
.append(" left join m_appuser dbu on dbu.id = l.disbursedon_userid")
.append(" left join m_appuser cbu on cbu.id = l.closedon_userid")
.append(" left join m_loan_arrears_aging la on la.loan_id = l.id");
.append(" left join m_loan_arrears_aging la on la.loan_id = l.id")
.append(" left join glim_accounts glim on glim.id=l.glim_id");
return accountsSummary.toString();
}
@@ -447,6 +491,7 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
final Long id = JdbcSupport.getLong(rs, "id");
final String accountNo = rs.getString("accountNo");
final String parentAccountNumber=rs.getString("parentAccountNumber");
final String externalId = rs.getString("externalId");
final Long productId = JdbcSupport.getLong(rs, "productId");
final String loanProductName = rs.getString("productName");
@@ -509,7 +554,7 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
disbursedByFirstname, disbursedByLastname, closedOnDate, closedByUsername, closedByFirstname, closedByLastname,
expectedMaturityDate, writtenOffOnDate, closedByUsername, closedByFirstname, closedByLastname);
return new LoanAccountSummaryData(id, accountNo, externalId, productId, loanProductName, shortLoanProductName, loanStatus, loanType, loanCycle,
return new LoanAccountSummaryData(id, accountNo,parentAccountNumber, externalId, productId, loanProductName, shortLoanProductName, loanStatus, loanType, loanCycle,
timeline, inArrears,originalLoan,loanBalance,amountPaid);
}
@@ -47,6 +47,9 @@ public class AccountEnumerations {
case JLG:
optionData = new EnumOptionData(AccountType.JLG.getValue().longValue(), AccountType.JLG.getCode(), "JLG");
break;
case GLIM:
optionData = new EnumOptionData(AccountType.GLIM.getValue().longValue(), AccountType.GLIM.getCode(), "GLIM");
break;
}
return optionData;
@@ -51,4 +51,6 @@ public interface CalendarReadPlatformService {
Boolean isCalendarAssociatedWithEntity(final Long entityId, final Long calendarId, Long entityTypeId);
}
@@ -33,6 +33,7 @@ import io.swagger.annotations.Tag;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -88,15 +89,18 @@ import org.apache.fineract.portfolio.group.data.GroupRoleData;
import org.apache.fineract.portfolio.group.service.CenterReadPlatformService;
import org.apache.fineract.portfolio.group.service.GroupReadPlatformService;
import org.apache.fineract.portfolio.group.service.GroupRolesReadPlatformService;
import org.apache.fineract.portfolio.loanaccount.data.GLIMContainer;
import org.apache.fineract.portfolio.loanaccount.service.GLIMAccountInfoReadPlatformService;
import org.apache.fineract.portfolio.meeting.data.MeetingData;
import org.apache.fineract.portfolio.meeting.service.MeetingReadPlatformService;
import org.apache.fineract.portfolio.savings.data.GSIMContainer;
import org.apache.fineract.portfolio.savings.service.GSIMReadPlatformService;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
@Path("/groups")
@Component
@Scope("singleton")
@@ -113,6 +117,8 @@ public class GroupsApiResource {
private final ToApiJsonSerializer<Object> toApiJsonSerializer;
private final ToApiJsonSerializer<GroupGeneralData> groupGeneralApiJsonSerializer;
private final ToApiJsonSerializer<AccountSummaryCollectionData> groupSummaryToApiJsonSerializer;
private final ToApiJsonSerializer<GLIMContainer> glimContainerToApiJsonSerializer;
private final ToApiJsonSerializer<GSIMContainer> gsimContainerToApiJsonSerializer;
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final CollectionSheetReadPlatformService collectionSheetReadPlatformService;
@@ -124,6 +130,8 @@ public class GroupsApiResource {
private final EntityDatatableChecksReadService entityDatatableChecksReadService;
private final BulkImportWorkbookService bulkImportWorkbookService;
private final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService;
private final GLIMAccountInfoReadPlatformService glimAccountInfoReadPlatformService;
private final GSIMReadPlatformService gsimReadPlatformService;
@Autowired
@@ -132,6 +140,8 @@ public class GroupsApiResource {
final ToApiJsonSerializer<Object> toApiJsonSerializer,
final ToApiJsonSerializer<GroupGeneralData> groupTopOfHierarchyApiJsonSerializer,
final ToApiJsonSerializer<AccountSummaryCollectionData> groupSummaryToApiJsonSerializer,
final ToApiJsonSerializer<GLIMContainer> glimContainerToApiJsonSerializer,
final ToApiJsonSerializer<GSIMContainer> gsimContainerToApiJsonSerializer,
final ApiRequestParameterHelper apiRequestParameterHelper,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
final CollectionSheetReadPlatformService collectionSheetReadPlatformService, final FromJsonHelper fromJsonHelper,
@@ -140,15 +150,18 @@ public class GroupsApiResource {
final CalendarReadPlatformService calendarReadPlatformService, final MeetingReadPlatformService meetingReadPlatformService,
final EntityDatatableChecksReadService entityDatatableChecksReadService,
final BulkImportWorkbookService bulkImportWorkbookService,
final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService) {
this.context = context;
final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService,
final GLIMAccountInfoReadPlatformService glimAccountInfoReadPlatformService,
final GSIMReadPlatformService gsimReadPlatformService) {
this.context = context;
this.groupReadPlatformService = groupReadPlatformService;
this.centerReadPlatformService = centerReadPlatformService;
this.clientReadPlatformService = clientReadPlatformService;
this.toApiJsonSerializer = toApiJsonSerializer;
this.groupGeneralApiJsonSerializer = groupTopOfHierarchyApiJsonSerializer;
this.groupSummaryToApiJsonSerializer = groupSummaryToApiJsonSerializer;
this.glimContainerToApiJsonSerializer=glimContainerToApiJsonSerializer;
this.gsimContainerToApiJsonSerializer=gsimContainerToApiJsonSerializer;
this.apiRequestParameterHelper = apiRequestParameterHelper;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.collectionSheetReadPlatformService = collectionSheetReadPlatformService;
@@ -160,6 +173,9 @@ public class GroupsApiResource {
this.entityDatatableChecksReadService = entityDatatableChecksReadService;
this.bulkImportWorkbookPopulatorService=bulkImportWorkbookPopulatorService;
this.bulkImportWorkbookService=bulkImportWorkbookService;
this.glimAccountInfoReadPlatformService=glimAccountInfoReadPlatformService;
this.gsimReadPlatformService=gsimReadPlatformService;
}
@GET
@@ -482,13 +498,14 @@ public class GroupsApiResource {
final AccountSummaryCollectionData groupAccount = this.accountDetailsReadPlatformService.retrieveGroupAccountDetails(groupId);
final Set<String> GROUP_ACCOUNTS_DATA_PARAMETERS = new HashSet<>(Arrays.asList("loanAccounts", "savingsAccounts",
final Set<String> GROUP_ACCOUNTS_DATA_PARAMETERS = new HashSet<>(Arrays.asList("loanAccounts", "groupLoanIndividualMonitoringAccounts","savingsAccounts",
"memberLoanAccounts", "memberSavingsAccounts"));
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.groupSummaryToApiJsonSerializer.serialize(settings, groupAccount, GROUP_ACCOUNTS_DATA_PARAMETERS);
}
@GET
@Path("downloadtemplate")
@Produces("application/vnd.ms-excel")
@@ -508,4 +525,64 @@ public class GroupsApiResource {
uploadedInputStream,fileDetail,locale,dateFormat);
return this.toApiJsonSerializer.serialize(importDocumentId);
}
@GET
@Path("{groupId}/glimaccounts")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveglimAccounts(@PathParam("groupId") final Long groupId, @QueryParam("parentLoanAccountNo")final String parentLoanAccountNo, @Context final UriInfo uriInfo)
{
this.context.authenticatedUser().validateHasReadPermission("GROUP");
List<GLIMContainer> glimContainer = Collections.emptyList();
if(parentLoanAccountNo==null)
{
glimContainer=(List)glimAccountInfoReadPlatformService.findGlimAccount(groupId);
}
else
{
glimContainer=(List)glimAccountInfoReadPlatformService.findGlimAccountbyGroupAndAccount(groupId,parentLoanAccountNo);
}
final Set<String> GLIM_ACCOUNTS_DATA_PARAMETERS = new HashSet<>(Arrays.asList("groupId", "accountNumber","childGLIMAccounts","memberLoanAccounts", "parentPrincipalAmount"));
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.glimContainerToApiJsonSerializer.serialize(settings, glimContainer, GLIM_ACCOUNTS_DATA_PARAMETERS);
}
@GET
@Path("{groupId}/gsimaccounts")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveGsimAccounts(@PathParam("groupId") final Long groupId, @QueryParam("parentGSIMAccountNo")final String parentGSIMAccountNo,
@QueryParam("parentGSIMId")final Long parentGSIMId,@Context final UriInfo uriInfo)
{
List<GSIMContainer> gsimContainer;
this.context.authenticatedUser().validateHasReadPermission("GROUP");
if(parentGSIMAccountNo==null && parentGSIMId!=null)
{
gsimContainer= (List<GSIMContainer>)this.gsimReadPlatformService.findGsimAccountContainerbyGsimAccountId(parentGSIMId);
}
else if(parentGSIMAccountNo !=null && parentGSIMId==null )
{
gsimContainer= (List)this.gsimReadPlatformService.findGsimAccountContainerbyGsimAccountNumber(parentGSIMAccountNo);
}
else
{
gsimContainer= (List)this.gsimReadPlatformService.findGSIMAccountContainerByGroupId(groupId);
}
final Set<String> GSIM_ACCOUNTS_DATA_PARAMETERS = new HashSet<>(Arrays.asList("gsimId","groupId", "accountNumber","childGSIMAccounts",
"parentBalance", "savingsStatus"));
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.gsimContainerToApiJsonSerializer.serialize(settings, gsimContainer, GSIM_ACCOUNTS_DATA_PARAMETERS);
}
}
@@ -58,6 +58,7 @@ import org.apache.fineract.portfolio.group.exception.ClientNotInGroupException;
import org.apache.fineract.portfolio.group.exception.GroupExistsInCenterException;
import org.apache.fineract.portfolio.group.exception.GroupNotExistsInCenterException;
import org.apache.fineract.portfolio.group.exception.InvalidGroupStateTransitionException;
import org.apache.fineract.portfolio.loanaccount.domain.GroupLoanIndividualMonitoringAccount;
import org.apache.fineract.useradministration.domain.AppUser;
import org.joda.time.LocalDate;
@@ -144,6 +145,9 @@ public final class Group extends AbstractPersistableCustom {
@OneToMany(mappedBy="group",cascade = CascadeType.REMOVE)
private Set<GroupRole> groupRole;
@OneToMany(mappedBy = "group")
private List<GroupLoanIndividualMonitoringAccount> glimLoan;
// JPA default constructor for entity
protected Group() {
@@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.group.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class GroupMemberNotFoundInGSIMException extends AbstractPlatformDomainRuleException
{
public GroupMemberNotFoundInGSIMException(final Long clientId)
{
super("error.msg.Group.member.not.found.in.linked.gsim", "The client with id `" + clientId + "` is not present in GSIM", clientId);
}
}
@@ -31,6 +31,7 @@ public interface LoanApiConstants {
public static final String loanChargeIdParameterName = "loanChargeId";
public static final String principalDisbursedParameterName = "transactionAmount";
public static final String chargesParameterName = "charges";
public static final String loanIdTobeApproved="loanId";
public static final String approvedLoanAmountParameterName = "approvedLoanAmount";
public static final String approvedOnDateParameterName = "approvedOnDate";
@@ -109,6 +110,8 @@ public interface LoanApiConstants {
public static final String dueDateParamName = "dueDate";
public static final String modifiedDueDateParamName = "modifiedDueDate";
public static final String principalParamName = "principal";
public static final String parentAccountParamName="isParentAccount";
public static final String totalLoanParamName="totalLoan";
public static final String installmentAmountParamName = "installmentAmount";
//loan write off
public static final String WRITEOFFREASONS = "WriteOffReasons";
@@ -126,4 +129,7 @@ public interface LoanApiConstants {
public static final String datatables = "datatables";
public static final String isEqualAmortizationParam = "isEqualAmortization";
public static final String applicationId = "applicationId";
public static final String lastApplication = "lastApplication";
}
@@ -105,6 +105,7 @@ import org.apache.fineract.portfolio.fund.service.FundReadPlatformService;
import org.apache.fineract.portfolio.group.data.GroupGeneralData;
import org.apache.fineract.portfolio.group.service.GroupReadPlatformService;
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
import org.apache.fineract.portfolio.loanaccount.data.GlimRepaymentTemplate;
import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData;
import org.apache.fineract.portfolio.loanaccount.data.LoanApprovalData;
import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
@@ -121,6 +122,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleD
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformService;
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryReadPlatformService;
import org.apache.fineract.portfolio.loanaccount.service.GLIMAccountInfoReadPlatformService;
import org.apache.fineract.portfolio.loanaccount.service.LoanChargeReadPlatformService;
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
@@ -265,6 +267,8 @@ public class LoansApiResource {
LoanApiConstants.datatables, LoanProductConstants.ratesParamName));
private final Set<String> LOAN_APPROVAL_DATA_PARAMETERS = new HashSet<>(Arrays.asList("approvalDate", "approvalAmount"));
final Set<String> GLIM_ACCOUNTS_DATA_PARAMETERS = new HashSet<>(Arrays.asList("glimId","groupId", "clientId","parentLoanAccountNo","parentPrincipalAmount",
"childLoanAccountNo", "childPrincipalAmount","clientName"));
private final String resourceNameForPermissions = "LOAN";
private final PlatformSecurityContext context;
@@ -296,6 +300,8 @@ public class LoansApiResource {
private final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService;
private final RateReadService rateReadService;
private final ConfigurationDomainService configurationDomainService;
private final DefaultToApiJsonSerializer<GlimRepaymentTemplate> glimTemplateToApiJsonSerializer;
private final GLIMAccountInfoReadPlatformService glimAccountInfoReadPlatformService;
@Autowired
public LoansApiResource(final PlatformSecurityContext context, final LoanReadPlatformService loanReadPlatformService,
@@ -319,7 +325,8 @@ public class LoansApiResource {
final EntityDatatableChecksReadService entityDatatableChecksReadService,
final BulkImportWorkbookService bulkImportWorkbookService,
final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService, final RateReadService rateReadService,
final ConfigurationDomainService configurationDomainService) {
final ConfigurationDomainService configurationDomainService, final DefaultToApiJsonSerializer<GlimRepaymentTemplate> glimTemplateToApiJsonSerializer,
final GLIMAccountInfoReadPlatformService glimAccountInfoReadPlatformService) {
this.context = context;
this.loanReadPlatformService = loanReadPlatformService;
this.loanProductReadPlatformService = loanProductReadPlatformService;
@@ -349,6 +356,8 @@ public class LoansApiResource {
this.bulkImportWorkbookService=bulkImportWorkbookService;
this.bulkImportWorkbookPopulatorService=bulkImportWorkbookPopulatorService;
this.configurationDomainService = configurationDomainService;
this.glimTemplateToApiJsonSerializer=glimTemplateToApiJsonSerializer;
this.glimAccountInfoReadPlatformService=glimAccountInfoReadPlatformService;
}
/*
@@ -918,6 +927,57 @@ public class LoansApiResource {
return bulkImportWorkbookPopulatorService.getTemplate(GlobalEntityType.LOANS.toString(), officeId, staffId,dateFormat);
}
@GET
@Path("glimAccount/{glimId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String getGlimRepaymentTemplate(@PathParam("glimId") final Long glimId,@Context final UriInfo uriInfo)
{
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
Collection<GlimRepaymentTemplate> glimRepaymentTemplate=this.glimAccountInfoReadPlatformService.findglimRepaymentTemplate(glimId);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.glimTemplateToApiJsonSerializer.serialize(settings, glimRepaymentTemplate, this.GLIM_ACCOUNTS_DATA_PARAMETERS);
}
@POST
@Path("glimAccount/{glimId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@ApiOperation(value = "Approve GLIM Application | Undo GLIM Application Approval | Reject GLIM Application | Disburse Loan Disburse Loan To Savings Account | Undo Loan Disbursal", httpMethod = "POST", notes = "Approve GLIM Application:\n" + "Mandatory Fields: approvedOnDate\n" + "Optional Fields: approvedLoanAmount and expectedDisbursementDate\n" + "Approves the GLIM application\n\n" + "Undo GLIM Application Approval:\n" + "Undoes the GLIM Application Approval\n\n" + "Reject GLIM Application:\n" + "Mandatory Fields: rejectedOnDate\n" + "Allows you to reject the GLIM application\n\n" + "Disburse Loan:\n" + "Mandatory Fields: actualDisbursementDate\n" + "Optional Fields: transactionAmount and fixedEmiAmount\n" + "Disburses the Loan\n\n" + "Disburse Loan To Savings Account:\n" + "Mandatory Fields: actualDisbursementDate\n" + "Optional Fields: transactionAmount and fixedEmiAmount\n" + "Disburses the loan to Saving Account\n\n" + "Undo Loan Disbursal:\n" + "Undoes the Loan Disbursal\n")
@ApiImplicitParams({@ApiImplicitParam(value = "body", required = true, paramType = "body", dataType = "body", format = "body", dataTypeClass = LoansApiResourceSwagger.PostLoansLoanIdRequest.class)})
@ApiResponses({@ApiResponse(code = 200, message = "OK", response = LoansApiResourceSwagger.PostLoansLoanIdResponse.class)})
public String glimStateTransitions(@PathParam("glimId") final Long glimId, @QueryParam("command") final String commandParam,
final String apiRequestBodyAsJson) {
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
CommandProcessingResult result = null;
if (is(commandParam, "reject")) {
final CommandWrapper commandRequest = builder.rejectGLIMApplication(glimId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "approve")) {
final CommandWrapper commandRequest = builder.approveGLIMLoanApplication(glimId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "disburse")) {
final CommandWrapper commandRequest = builder.disburseGlimLoanApplication(glimId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "glimrepayment")) {
final CommandWrapper commandRequest = builder.repaymentGlimLoanApplication(glimId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "undodisbursal")) {
final CommandWrapper commandRequest = builder.undoGLIMLoanDisbursal(glimId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "undoapproval")) {
final CommandWrapper commandRequest = builder.undoGLIMLoanApproval(glimId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
}
if (result == null) { throw new UnrecognizedQueryParamException("command", commandParam); }
return this.toApiJsonSerializer.serialize(result);
}
@GET
@Path("repayments/downloadtemplate")
@Produces("application/vnd.ms-excel")
@@ -0,0 +1,73 @@
/**
* 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.data;
import java.math.BigDecimal;
import java.util.List;
import org.apache.fineract.portfolio.accountdetails.data.LoanAccountSummaryData;
public class GLIMContainer {
private final BigDecimal glimId;
private final BigDecimal groupId;
private final String accountNumber;
private final List<LoanAccountSummaryData> childGLIMAccounts;
private final BigDecimal parentPrincipalAmount;
private final String loanStatus;
public GLIMContainer(final BigDecimal glimId,final BigDecimal groupId,final String accountNumber,final List<LoanAccountSummaryData> childGLIMAccounts,
final BigDecimal parentPrincipalAmount,final String loanStatus) {
this.glimId=glimId;
this.groupId=groupId;
this.accountNumber = accountNumber;
this.childGLIMAccounts=childGLIMAccounts;
this.parentPrincipalAmount = parentPrincipalAmount;
this.loanStatus=loanStatus;
}
public BigDecimal getGlimId() {
return glimId;
}
public BigDecimal getGroupId() {
return groupId;
}
public String getAccountNumber() {
return accountNumber;
}
public List<LoanAccountSummaryData> getChildGLIMAccounts() {
return childGLIMAccounts;
}
public BigDecimal getParentPrincipalAmount() {
return parentPrincipalAmount;
}
public String getLoanStatus() {
return loanStatus;
}
}
@@ -0,0 +1,105 @@
/**
* 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.data;
import java.math.BigDecimal;
public class GlimRepaymentTemplate
{
private final BigDecimal glimId;
private final BigDecimal groupId;
private final BigDecimal clientId;
private final String clientName;
private final BigDecimal childLoanId;
private final String parentAccountNo;
private final BigDecimal parentPrincipalAmount;
private final String childLoanAccountNo;
private final BigDecimal childPrincipalAmount ;
private GlimRepaymentTemplate(final BigDecimal glimId,final BigDecimal groupId,final BigDecimal clientId,
final String clientName,final BigDecimal childLoanId,final String parentAccountNo,final BigDecimal parentPrincipalAmount,
final String childLoanAccountNo,final BigDecimal childPrincipalAmount)
{
this.glimId=glimId;
this.groupId=groupId;
this.clientId=clientId;
this.clientName=clientName;
this.childLoanId=childLoanId;
this.parentAccountNo=parentAccountNo;
this.parentPrincipalAmount=parentPrincipalAmount;
this.childLoanAccountNo=childLoanAccountNo;
this.childPrincipalAmount=childPrincipalAmount;
}
public static GlimRepaymentTemplate getInstance(final BigDecimal glimId,final BigDecimal groupId,final BigDecimal clientId,
final String clientName,final BigDecimal childLoanId,final String parentAccountNo,final BigDecimal parentPrincipalAmount,
final String childLoanAccountNo,final BigDecimal childPrincipalAmount)
{
return new GlimRepaymentTemplate(glimId,groupId,clientId,clientName,childLoanId,parentAccountNo,
parentPrincipalAmount,childLoanAccountNo,childPrincipalAmount);
}
public BigDecimal getGlimId() {
return glimId;
}
public BigDecimal getGroupId() {
return groupId;
}
public BigDecimal getClientId() {
return clientId;
}
public String getClientName() {
return clientName;
}
public BigDecimal getChildLoanId() {
return childLoanId;
}
public String getParentAccountNo() {
return parentAccountNo;
}
public BigDecimal getParentPrincipalAmount() {
return parentPrincipalAmount;
}
public String getChildLoanAccountNo() {
return childLoanAccountNo;
}
public BigDecimal getChildPrincipalAmount() {
return childPrincipalAmount;
}
}
@@ -0,0 +1,103 @@
/**
* 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.data;
import java.math.BigDecimal;
public class GroupLoanIndividualMonitoringAccountData
{
private final BigDecimal glimId;
private final BigDecimal groupId;
private final String accountNumber;
private final String childAccountNumber;
private final BigDecimal childPrincipalAmount;
private final BigDecimal parentPrincipalAmount;
private final Long childAccountsCount;
private final String loanStatus;
private GroupLoanIndividualMonitoringAccountData(final BigDecimal glimId,final BigDecimal groupId,final String accountNumber, final String childAccountNumber,
final BigDecimal childPrincipalAmount, final BigDecimal parentPrincipalAmount,
final Long childAccountsCount,final String loanStatus) {
this.glimId=glimId;
this.groupId=groupId;
this.accountNumber = accountNumber;
this.childAccountNumber = childAccountNumber;
this.childPrincipalAmount = childPrincipalAmount;
this.parentPrincipalAmount = parentPrincipalAmount;
this.childAccountsCount = childAccountsCount;
this.loanStatus=loanStatus;
}
public static GroupLoanIndividualMonitoringAccountData getInstance(final BigDecimal glimId, final BigDecimal groupId,final String accountNumber, final String childAccountNumber,
final BigDecimal childPrincipalAmount, final BigDecimal parentPrincipalAmount,
final Long childAccountsCount,final String loanStatus)
{
return new GroupLoanIndividualMonitoringAccountData(glimId,groupId,accountNumber,childAccountNumber,
childPrincipalAmount,parentPrincipalAmount,childAccountsCount,loanStatus);
}
public static GroupLoanIndividualMonitoringAccountData getInstance1(final BigDecimal glimId,final BigDecimal groupId,final String accountNumber,
final BigDecimal parentPrincipalAmount,final String loanStatus)
{
return new GroupLoanIndividualMonitoringAccountData(glimId,groupId,accountNumber,null,null,parentPrincipalAmount,null,loanStatus);
}
public BigDecimal getGlimId() {
return glimId;
}
public BigDecimal getGroupId() {
return groupId;
}
public String getAccountNumber() {
return accountNumber;
}
public String getChildAccountNumber() {
return childAccountNumber;
}
public BigDecimal getChildPrincipalAmount() {
return childPrincipalAmount;
}
public BigDecimal getParentPrincipalAmount() {
return parentPrincipalAmount;
}
public Long getChildAccountsCount() {
return childAccountsCount;
}
public String getLoanStatus() {
return loanStatus;
}
}
@@ -0,0 +1,34 @@
/**
* 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.domain;
import java.math.BigDecimal;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface GLIMAccountInfoRepository extends JpaRepository<GroupLoanIndividualMonitoringAccount, Long>,
JpaSpecificationExecutor<GroupLoanIndividualMonitoringAccount> {
GroupLoanIndividualMonitoringAccount findOneByIsAcceptingChild(boolean acceptingChild);
GroupLoanIndividualMonitoringAccount findOneByIsAcceptingChildAndApplicationId(boolean acceptingChild,
BigDecimal applicationId);
GroupLoanIndividualMonitoringAccount findOneByAccountNumber(String accountNumber);
}
@@ -0,0 +1,146 @@
/**
* 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.domain;
import java.math.BigDecimal;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.portfolio.group.domain.Group;
@Entity
@Table(name = "glim_accounts", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_number" }, name = "FK_glim_id")})
public class GroupLoanIndividualMonitoringAccount extends AbstractPersistableCustom {
@ManyToOne
@JoinColumn(name = "group_id", nullable = false)
private Group group;
@Column(name = "account_number", nullable = false)
private String accountNumber;
@Column(name = "principal_amount")
private BigDecimal principalAmount;
@Column(name = "child_accounts_count")
private Long childAccountsCount;
@Column(name = "accepting_child")
private Boolean isAcceptingChild;
@OneToMany
private Set<Loan> childLoan;
@Column(name = "loan_status_id", nullable = false)
private Integer loanStatus;
@Column(name = "application_id", nullable = true)
private BigDecimal applicationId;
private GroupLoanIndividualMonitoringAccount(String accountNumber,Group group,BigDecimal principalAmount,Long childAccountsCount,
Boolean isAcceptingChild,Integer loanStatus,BigDecimal applicationId)
{
this.accountNumber=accountNumber;
this.group=group;
this.principalAmount=principalAmount;
this.childAccountsCount=childAccountsCount;
this.isAcceptingChild=isAcceptingChild;
this.loanStatus=loanStatus;
this.applicationId=applicationId;
}
public static GroupLoanIndividualMonitoringAccount getInstance(String accountNumber,Group group,BigDecimal principalAmount,Long childAccountsCount,
Boolean isAcceptingChild,Integer loanStatus,BigDecimal applicationId)
{
return new GroupLoanIndividualMonitoringAccount(accountNumber,group,principalAmount,childAccountsCount,
isAcceptingChild,loanStatus,applicationId);
}
public String getAccountNumber() {
return accountNumber;
}
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
public void setAccountNumber(String accountNumber) {
this.accountNumber = accountNumber;
}
public Set<Loan> getChildLoan() {
return childLoan;
}
public void setChildLoan(Set<Loan> childLoan) {
this.childLoan = childLoan;
}
public BigDecimal getPrincipalAmount() {
return principalAmount;
}
public void setPrincipalAmount(BigDecimal principalAmount) {
this.principalAmount = principalAmount;
}
public Long getChildAccountsCount() {
return childAccountsCount;
}
public void setChildAccountsCount(Long childAccountsCount) {
this.childAccountsCount = childAccountsCount;
}
public Boolean getIsAcceptingChild() {
return isAcceptingChild;
}
public void setIsAcceptingChild(Boolean isAcceptingChild) {
this.isAcceptingChild = isAcceptingChild;
}
public Integer getLoanStatus() {
return loanStatus;
}
public void setLoanStatus(Integer loanStatus) {
this.loanStatus = loanStatus;
}
public BigDecimal getApplicationId() {
return applicationId;
}
public void setApplicationId(BigDecimal applicationId) {
this.applicationId = applicationId;
}
}
@@ -167,6 +167,10 @@ public class Loan extends AbstractPersistableCustom {
@JoinColumn(name = "group_id", nullable = true)
private Group group;
@ManyToOne
@JoinColumn(name = "glim_id", nullable = true)
private GroupLoanIndividualMonitoringAccount glim;
@Column(name = "loan_type_enum", nullable = false)
private Integer loanType;
@@ -627,6 +631,7 @@ public class Loan extends AbstractPersistableCustom {
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), charges());
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
mapEntry.getValue().updateLoan(this);
}
this.loanTransactions.addAll(changedTransactionDetail.getNewTransactionMappings().values());
@@ -675,6 +680,7 @@ public class Loan extends AbstractPersistableCustom {
final LoanTransaction applyLoanChargeTransaction = LoanTransaction.accrueLoanCharge(this, getOffice(), chargeAmount,
transactionDate, feeCharges, penaltyCharges, DateUtils.getLocalDateTimeOfTenant(), currentUser);
Integer installmentNumber = null;
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(applyLoanChargeTransaction, loanCharge, loanCharge.getAmount(
getCurrency()).getAmount(), installmentNumber);
@@ -701,6 +707,7 @@ public class Loan extends AbstractPersistableCustom {
List<LoanRepaymentScheduleInstallment> installments = getRepaymentScheduleInstallments() ;
for (final LoanRepaymentScheduleInstallment installment : installments) {
if (installmentNumber == null && charge.isDueForCollectionFromAndUpToAndIncluding(startDate, installment.getDueDate())) {
chargePaymentInstallments.add(installment);
break;
} else if (installmentNumber != null && installment.getInstallmentNumber().equals(installmentNumber)) {
@@ -712,6 +719,7 @@ public class Loan extends AbstractPersistableCustom {
final Set<LoanCharge> loanCharges = new HashSet<>(1);
loanCharges.add(charge);
loanRepaymentScheduleTransactionProcessor.handleTransaction(chargesPayment, getCurrency(), chargePaymentInstallments, loanCharges);
updateLoanSummaryDerivedFields();
doPostLoanTransactionChecks(chargesPayment.getTransactionDate(), loanLifecycleStateMachine);
}
@@ -720,6 +728,7 @@ public class Loan extends AbstractPersistableCustom {
if (isClosed()) {
final String defaultUserMessage = "This charge cannot be added as the loan is already closed.";
throw new LoanChargeCannotBeAddedException("loanCharge", "loan.is.closed", defaultUserMessage, getId(), loanCharge.name());
}
}
@@ -727,6 +736,7 @@ public class Loan extends AbstractPersistableCustom {
if (loanCharge.isWaived()) {
final String defaultUserMessage = "This loan charge cannot be removed as the charge as already been waived.";
throw new LoanChargeCannotBeAddedException("loanCharge", "loanCharge.is.waived", defaultUserMessage, getId(), loanCharge.name());
}
}
@@ -805,6 +815,7 @@ public class Loan extends AbstractPersistableCustom {
final Money penaltychargesPortion = Money.zero(currency);
transaction.updateComponentsAndTotal(principalPortion, interestPortion, chargeAmount, penaltychargesPortion);
} else {
transactionToRemove = transaction;
}
@@ -1072,6 +1083,14 @@ public class Loan extends AbstractPersistableCustom {
return this.client;
}
public GroupLoanIndividualMonitoringAccount getGlim() {
return glim;
}
public void setGlim(GroupLoanIndividualMonitoringAccount glim) {
this.glim = glim;
}
public LoanProduct loanProduct() {
return this.loanProduct;
}
@@ -4203,6 +4222,14 @@ public class Loan extends AbstractPersistableCustom {
return groupId;
}
public Long getGlimId() {
Long glimId = null;
if (this.glim != null) {
glimId = this.glim.getId();
}
return glimId;
}
public Long getOfficeId() {
Long officeId = null;
if (this.client != null) {
@@ -6558,4 +6585,13 @@ public class Loan extends AbstractPersistableCustom {
public List<Rate> getRates() {
return rates;
}
public Integer getLoanType() {
return loanType;
}
public void setLoanType(Integer loanType) {
this.loanType = loanType;
}
}
@@ -120,6 +120,9 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
@Query("select loan from Loan loan where loan.group.id = :groupId and loan.client.id is null")
List<Loan> findByGroupId(@Param("groupId") Long groupId);
@Query("select loan from Loan loan where loan.glim.id = :glimId")
List<Loan> findByGlimId(@Param("glimId") Long glimId);
@Query("select loan from Loan loan where loan.id IN :ids and loan.loanStatus IN :loanStatuses and loan.loanType IN :loanTypes")
List<Loan> findByIdsAndLoanStatusAndLoanType(@Param("ids") Collection<Long> ids,
@Param("loanStatuses") Collection<Integer> loanStatuses, @Param("loanTypes") Collection<Integer> loanTypes);
@@ -153,4 +156,5 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
@Query(FIND_NON_CLOSED_LOAN_THAT_BELONGS_TO_CLIENT)
Loan findNonClosedLoanThatBelongsToClient(@Param("loanId") Long loanId, @Param("clientId") Long clientId);
}
@@ -59,6 +59,7 @@ public class LoanRepositoryWrapper {
return loan;
}
//Root Entities are enough
public Collection<Loan> findActiveLoansByLoanIdAndGroupId(Long clientId, Long groupId) {
final Collection<Integer> loanStatuses = new ArrayList<>(Arrays.asList(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue(),
@@ -45,4 +45,5 @@ public interface GuarantorReadPlatformService {
List<ObligeeData> retrieveObligeeDetails(Long clientId);
}
@@ -88,6 +88,7 @@ public class GuarantorReadPlatformServiceImpl implements GuarantorReadPlatformSe
return mergedGuarantorDatas;
}
@Override
public GuarantorData retrieveGuarantor(final Long loanId, final Long guarantorId) {
final GuarantorMapper rm = new GuarantorMapper();
@@ -0,0 +1,49 @@
/**
* 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.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.loanaccount.service.LoanApplicationWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "GLIMLOAN", action = "REJECT")
public class GLIMApplicationRejectionCommandHandler implements NewCommandSourceHandler
{
private final LoanApplicationWritePlatformService writePlatformService;
@Autowired
public GLIMApplicationRejectionCommandHandler(final LoanApplicationWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.rejectGLIMApplicationApproval(command.entityId(), command);
}
}
@@ -0,0 +1,49 @@
/**
* 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.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "GLIMLOAN", action = "REPAYMENT")
public class GLIMBulkRepaymentCommandHandler implements NewCommandSourceHandler {
private final LoanWritePlatformService writePlatformService;
@Autowired
public GLIMBulkRepaymentCommandHandler(final LoanWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.makeGLIMLoanRepayment(command.entityId(), command);
}
}
@@ -0,0 +1,49 @@
/**
* 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.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.loanaccount.service.LoanApplicationWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "GLIMLOAN", action = "APPROVE")
public class GLIMLoanApplicationApprovalCommandHandler implements NewCommandSourceHandler {
private final LoanApplicationWritePlatformService writePlatformService;
@Autowired
public GLIMLoanApplicationApprovalCommandHandler(final LoanApplicationWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.approveGLIMLoanAppication(command.entityId(), command);
}
}
@@ -0,0 +1,52 @@
/**
* 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.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "GLIMLOAN", action = "DISBURSE")
public class GlimLoanApplicationDisburseCommandHandler implements NewCommandSourceHandler
{
private final LoanWritePlatformService writePlatformService;
@Autowired
public GlimLoanApplicationDisburseCommandHandler(final LoanWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.disburseGLIMLoan(command.entityId(), command);
}
}
@@ -0,0 +1,49 @@
/**
* 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.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.loanaccount.service.LoanApplicationWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "GLIMLOAN", action = "UNDOAPPROVAL")
public class UndoGLIMLoanApplicationApproval implements NewCommandSourceHandler
{
private final LoanApplicationWritePlatformService writePlatformService;
@Autowired
public UndoGLIMLoanApplicationApproval(final LoanApplicationWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.undoGLIMLoanApplicationApproval(command.entityId(), command);
}
}
@@ -0,0 +1,49 @@
/**
* 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.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "GLIMLOAN", action = "UNDODISBURSAL")
public class UndoGLIMLoanDisbursalCommandHandler implements NewCommandSourceHandler
{
private final LoanWritePlatformService writePlatformService;
@Autowired
public UndoGLIMLoanDisbursalCommandHandler(final LoanWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.undoGLIMLoanDisbursal(command.entityId(), command);
}
}
@@ -29,4 +29,5 @@ public interface LoanScheduleCalculationPlatformService {
void updateFutureSchedule(LoanScheduleData loanScheduleData, Long loanId);
LoanScheduleData generateLoanScheduleForVariableInstallmentRequest(Long loanId, String json);
}
@@ -137,6 +137,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
return this.loanScheduleAssembler.assembleLoanScheduleFrom(query.parsedJson());
}
@Override
public void updateFutureSchedule(LoanScheduleData loanScheduleData, final Long loanId) {
@@ -62,7 +62,7 @@ public final class LoanApplicationCommandFromApiJsonHelper {
final Set<String> supportedParameters = new HashSet<>(Arrays.asList(LoanApiConstants.dateFormatParameterName,
LoanApiConstants.localeParameterName, LoanApiConstants.idParameterName, LoanApiConstants.clientIdParameterName,
LoanApiConstants.groupIdParameterName, LoanApiConstants.loanTypeParameterName, LoanApiConstants.productIdParameterName,
LoanApiConstants.principalParamName, LoanApiConstants.loanTermFrequencyParameterName,
LoanApiConstants.principalParamName,LoanApiConstants.totalLoanParamName,LoanApiConstants.parentAccountParamName, LoanApiConstants.loanTermFrequencyParameterName,
LoanApiConstants.loanTermFrequencyTypeParameterName, LoanApiConstants.numberOfRepaymentsParameterName,
LoanApiConstants.repaymentEveryParameterName, LoanApiConstants.repaymentFrequencyTypeParameterName,
LoanApiConstants.repaymentFrequencyNthDayTypeParameterName, LoanApiConstants.repaymentFrequencyDayOfWeekTypeParameterName,
@@ -91,7 +91,9 @@ public final class LoanApplicationCommandFromApiJsonHelper {
LoanApiConstants.linkAccountIdParameterName, LoanApiConstants.disbursementDataParameterName,
LoanApiConstants.emiAmountParameterName, LoanApiConstants.maxOutstandingBalanceParameterName,
LoanProductConstants.graceOnArrearsAgeingParameterName, LoanApiConstants.createStandingInstructionAtDisbursementParameterName,
LoanApiConstants.isTopup, LoanApiConstants.loanIdToClose, LoanApiConstants.datatables, LoanApiConstants.isEqualAmortizationParam, LoanProductConstants.ratesParamName));
LoanApiConstants.isTopup, LoanApiConstants.loanIdToClose, LoanApiConstants.datatables, LoanApiConstants.isEqualAmortizationParam,LoanProductConstants.ratesParamName,
LoanApiConstants.applicationId, // glim specific
LoanApiConstants.lastApplication)); // glim specific
private final FromJsonHelper fromApiJsonHelper;
private final CalculateLoanScheduleQueryFromApiJsonHelper apiJsonHelper;
@@ -120,7 +122,7 @@ public final class LoanApplicationCommandFromApiJsonHelper {
if (!StringUtils.isBlank(loanTypeStr)) {
final AccountType loanType = AccountType.fromName(loanTypeStr);
baseDataValidator.reset().parameter(loanTypeParameterName).value(loanType.getValue()).inMinMaxRange(1, 3);
baseDataValidator.reset().parameter(loanTypeParameterName).value(loanType.getValue()).inMinMaxRange(1, 4);
final Long clientId = this.fromApiJsonHelper.extractLongNamed("clientId", element);
final Long groupId = this.fromApiJsonHelper.extractLongNamed("groupId", element);
@@ -58,7 +58,7 @@ public final class LoanApplicationTransitionApiJsonValidator {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Set<String> disbursementParameters = new HashSet<>(Arrays.asList(LoanApiConstants.approvedLoanAmountParameterName,
final Set<String> disbursementParameters = new HashSet<>(Arrays.asList(LoanApiConstants.loanIdTobeApproved,LoanApiConstants.approvedLoanAmountParameterName,
LoanApiConstants.approvedOnDateParameterName, LoanApiConstants.noteParameterName, LoanApiConstants.localeParameterName,
LoanApiConstants.dateFormatParameterName,LoanApiConstants.disbursementDataParameterName,LoanApiConstants.disbursementDateParameterName));
@@ -155,7 +155,7 @@ public final class LoanEventApiJsonValidator {
final Set<String> transactionParameters = new HashSet<>(Arrays.asList("transactionDate", "transactionAmount", "externalId",
"note", "locale", "dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber",
"bankNumber"));
"bankNumber","loanId"));
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, transactionParameters);
@@ -0,0 +1,44 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.loanaccount.service;
import java.util.Collection;
import org.apache.fineract.portfolio.loanaccount.data.GLIMContainer;
import org.apache.fineract.portfolio.loanaccount.data.GlimRepaymentTemplate;
import org.apache.fineract.portfolio.loanaccount.data.GroupLoanIndividualMonitoringAccountData;
public interface GLIMAccountInfoReadPlatformService
{
Collection<GroupLoanIndividualMonitoringAccountData> findGlimAccountsByGroupId(String groupId);
Collection<GroupLoanIndividualMonitoringAccountData> findGlimAccountByGroupId(String groupId);
Collection<GLIMContainer> findGlimAccount(Long groupId);
Collection<GroupLoanIndividualMonitoringAccountData> findGlimAccountByGroupIdandAccountNo(String groupId, String accountNo);
Collection<GLIMContainer> findGlimAccountbyGroupAndAccount(Long groupId, String accountNo);
Collection<GroupLoanIndividualMonitoringAccountData> findGlimAccountByParentAccountId(String parentAccountIds);
Collection<GroupLoanIndividualMonitoringAccountData> findGlimAccountsByGLIMId(Long glimId);
Collection<GlimRepaymentTemplate> findglimRepaymentTemplate(Long glimId);
}
@@ -0,0 +1,262 @@
/**
* 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.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.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.accountdetails.data.LoanAccountSummaryData;
import org.apache.fineract.portfolio.accountdetails.service.AccountDetailsReadPlatformService;
import org.apache.fineract.portfolio.loanaccount.data.GLIMContainer;
import org.apache.fineract.portfolio.loanaccount.data.GlimRepaymentTemplate;
import org.apache.fineract.portfolio.loanaccount.data.GroupLoanIndividualMonitoringAccountData;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
@Service
public class GLIMAccountInfoReadPlatformServiceImpl implements GLIMAccountInfoReadPlatformService
{
private final JdbcTemplate jdbcTemplate;
private final PlatformSecurityContext context;
private final AccountDetailsReadPlatformService accountDetailsReadPlatforService;
@Autowired
public GLIMAccountInfoReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
final AccountDetailsReadPlatformService accountDetailsReadPlatforService) {
this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.accountDetailsReadPlatforService=accountDetailsReadPlatforService;
}
private static final class GLIMFieldsMapper implements RowMapper<GroupLoanIndividualMonitoringAccountData> {
public String schema() {
return "glim.id as glimId,ln.group_id as groupId,glim.account_number as accountNumber, ln.account_no as childAccountNumber,ln.principal_amount as childPrincipalAmount,glim.principal_amount as parentPrincipalAmount,glim.child_accounts_count as childAccountsCount,"
+"glim.loan_status_id as loanStatus from glim_accounts glim,m_loan ln where glim.id=ln.glim_id";
}
@Override
public GroupLoanIndividualMonitoringAccountData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum)
throws SQLException {
final BigDecimal glimId=rs.getBigDecimal("glimId");
final BigDecimal groupId=rs.getBigDecimal("groupId");
final String accountNumber=rs.getString("accountNumber");
final String childAccountNumber=rs.getString("childAccountNumber");
final Long childAccountsCount=rs.getLong("childAccountsCount");
final BigDecimal parentPrincipalAmount=rs.getBigDecimal("parentPrincipalAmount");
final BigDecimal childPrincipalAmount=rs.getBigDecimal("childPrincipalAmount");
final String loanStatus=LoanStatus.fromInt((int)rs.getLong("loanStatus")).toString();
return GroupLoanIndividualMonitoringAccountData.getInstance(glimId,groupId,accountNumber,childAccountNumber,childPrincipalAmount,parentPrincipalAmount,
childAccountsCount,loanStatus);
}
}
@Override
public Collection<GroupLoanIndividualMonitoringAccountData> findGlimAccountsByGLIMId(final Long glimId) {
this.context.authenticatedUser();
final GLIMFieldsMapper rm = new GLIMFieldsMapper();
final String sql = "select " + rm.schema() + " and glim.id=?";
return this.jdbcTemplate.query(sql, rm, new Object[] { glimId });
}
@Override
public Collection<GroupLoanIndividualMonitoringAccountData> findGlimAccountsByGroupId(String groupId) {
this.context.authenticatedUser();
final GLIMFieldsMapper rm = new GLIMFieldsMapper();
final String sql = "select " + rm.schema() + " and ln.group_id=?";
return this.jdbcTemplate.query(sql, rm, new Object[] { groupId });
}
@Override
public Collection<GroupLoanIndividualMonitoringAccountData> findGlimAccountByGroupId(String groupId) {
this.context.authenticatedUser();
GLIMMapper rm=new GLIMMapper();
final String sql="select "+rm.schema()+" where glim.group_id=?";
return this.jdbcTemplate.query(sql, rm, new Object[] { groupId });
}
@Override
public Collection<GroupLoanIndividualMonitoringAccountData> findGlimAccountByParentAccountId(String parentAccountIds) {
this.context.authenticatedUser();
final GLIMFieldsMapper rm = new GLIMFieldsMapper();
final String sql = "select " + rm.schema() + " and glim.accountNumber=?";
return this.jdbcTemplate.query(sql, rm, new Object[] { parentAccountIds });
}
@Override
public Collection<GroupLoanIndividualMonitoringAccountData> findGlimAccountByGroupIdandAccountNo(String groupId,String accountNo) {
this.context.authenticatedUser();
GLIMMapper rm=new GLIMMapper();
final String sql="select "+rm.schema()+" where glim.group_id=? and glim.account_number=?";
return this.jdbcTemplate.query(sql, rm, new Object[] { groupId,accountNo });
}
@Override
public Collection<GLIMContainer> findGlimAccount(Long groupId) {
this.context.authenticatedUser();
Collection<GroupLoanIndividualMonitoringAccountData> glimInfo=findGlimAccountByGroupId(groupId+"");
//List<LoanAccountSummaryData> glimAccounts = retrieveLoanAccountDetails(loanWhereClauseForGroupAndLoanType, new Object[] { groupId });
List<GLIMContainer> glimAccounts=new ArrayList<GLIMContainer>();
for(GroupLoanIndividualMonitoringAccountData glimAccount:glimInfo)
{
List<LoanAccountSummaryData> childLoans=accountDetailsReadPlatforService.retrieveLoanAccountDetailsByGroupIdAndGlimAccountNumber(groupId,glimAccount.getAccountNumber());
glimAccounts.add(new GLIMContainer(glimAccount.getGlimId(),glimAccount.getGroupId(), glimAccount.getAccountNumber(),
childLoans, glimAccount.getParentPrincipalAmount(),glimAccount.getLoanStatus()));
}
return glimAccounts;
}
@Override
public Collection<GLIMContainer> findGlimAccountbyGroupAndAccount(Long groupId,String accountNo) {
this.context.authenticatedUser();
Collection<GroupLoanIndividualMonitoringAccountData> glimInfo=findGlimAccountByGroupIdandAccountNo(groupId+"", accountNo+"");
//List<LoanAccountSummaryData> glimAccounts = retrieveLoanAccountDetails(loanWhereClauseForGroupAndLoanType, new Object[] { groupId });
List<GLIMContainer> glimAccounts=new ArrayList<GLIMContainer>();
for(GroupLoanIndividualMonitoringAccountData glimAccount:glimInfo)
{
List<LoanAccountSummaryData> childLoans=accountDetailsReadPlatforService.retrieveLoanAccountDetailsByGroupIdAndGlimAccountNumber(groupId,glimAccount.getAccountNumber());
glimAccounts.add(new GLIMContainer(glimAccount.getGlimId(),glimAccount.getGroupId(), glimAccount.getAccountNumber(),
childLoans, glimAccount.getParentPrincipalAmount(),glimAccount.getLoanStatus()));
}
return glimAccounts;
}
@Override
public Collection<GlimRepaymentTemplate> findglimRepaymentTemplate(final Long glimId)
{
this.context.authenticatedUser();
GLIMRepaymentMapper rm=new GLIMRepaymentMapper();
final String sql="select "+rm.schema()+" where glim.id=?";
return this.jdbcTemplate.query(sql, rm, new Object[] {glimId});
}
private static final class GLIMMapper implements RowMapper<GroupLoanIndividualMonitoringAccountData> {
public String schema() {
return "glim.id as glimId,glim.group_id as groupId,glim.account_number as accountNumber,glim.principal_amount as principalAmount,glim.child_accounts_count as childAccountsCount,"+
"glim.loan_status_id as loanStatus from glim_accounts glim";
}
@Override
public GroupLoanIndividualMonitoringAccountData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum)
throws SQLException {
final BigDecimal glimId=rs.getBigDecimal("glimId");
final BigDecimal groupId=rs.getBigDecimal("groupId");
final String accountNumber=rs.getString("accountNumber");
final BigDecimal principalAmount=rs.getBigDecimal("principalAmount");
final String loanStatus=LoanStatus.fromInt((int)rs.getLong("loanStatus")).toString();
return GroupLoanIndividualMonitoringAccountData.getInstance1(glimId,groupId, accountNumber, principalAmount,loanStatus);
}
}
private static final class GLIMRepaymentMapper implements RowMapper<GlimRepaymentTemplate> {
public String schema() {
return "glim.id as glimId,loan.group_id as groupId,client.id as clientId,glim.account_number as parentLoanAccountNo,"+
"glim.principal_amount as parentPrincipalAmount,loan.id as childLoanId,loan.account_no as childLoanAccountNo,loan.approved_principal as childPrincipalAmount,"+
"client.display_name as clientName from glim_accounts glim left join m_loan loan on loan.glim_id=glim.id "+
"left join m_client client on client.id=loan.client_id";
}
@Override
public GlimRepaymentTemplate mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum)
throws SQLException {
final BigDecimal glimId=rs.getBigDecimal("glimId");
final BigDecimal groupId=rs.getBigDecimal("groupId");
final BigDecimal clientId=rs.getBigDecimal("clientId");
final String clientName=rs.getString("clientName");
final BigDecimal childLoanId=rs.getBigDecimal("childLoanId");
final String parentLoanAccountNo=rs.getString("parentLoanAccountNo");
final BigDecimal parentPrincipalAmount=rs.getBigDecimal("parentPrincipalAmount");
final String childLoanAccountNo=rs.getString("childLoanAccountNo");
final BigDecimal childPrincipalAmount=rs.getBigDecimal("childPrincipalAmount");
return GlimRepaymentTemplate.getInstance(glimId,groupId,clientId,clientName,childLoanId,parentLoanAccountNo,
parentPrincipalAmount,childLoanAccountNo,childPrincipalAmount);
}
}
}
@@ -0,0 +1,36 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.loanaccount.service;
import java.math.BigDecimal;
import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.portfolio.loanaccount.domain.GroupLoanIndividualMonitoringAccount;
public interface GLIMAccountInfoWritePlatformService {
void setIsAcceptingChild(GroupLoanIndividualMonitoringAccount glimAccount);
void resetIsAcceptingChild(GroupLoanIndividualMonitoringAccount glimAccount);
void incrementChildAccountCount(GroupLoanIndividualMonitoringAccount glimAccount);
void addGLIMAccountInfo(String accountNumber, Group group, BigDecimal principalAmount, Long childAccountsCount,
Boolean isAcceptingChild, Integer loanStatus, BigDecimal applicationId);
}
@@ -0,0 +1,94 @@
/**
* 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.service;
import java.math.BigDecimal;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.portfolio.loanaccount.domain.GLIMAccountInfoRepository;
import org.apache.fineract.portfolio.loanaccount.domain.GroupLoanIndividualMonitoringAccount;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class GLIMAccountInfoWritePlatformServiceImpl implements GLIMAccountInfoWritePlatformService
{
private final PlatformSecurityContext context;
private final GLIMAccountInfoRepository glimAccountRepository;
private final LoanRepository loanRepository;
@Autowired
public GLIMAccountInfoWritePlatformServiceImpl(final PlatformSecurityContext context,final GLIMAccountInfoRepository glimAccountRepository,
final LoanRepository loanRepository)
{
this.context=context;
this.glimAccountRepository=glimAccountRepository;
this.loanRepository=loanRepository;
}
@Override
public void addGLIMAccountInfo(String accountNumber,Group group,BigDecimal principalAmount,Long childAccountsCount,
Boolean isAcceptingChild,Integer loanStatus,BigDecimal applicationId)
{
childAccountsCount=2L;
GroupLoanIndividualMonitoringAccount glimAccountInfo=GroupLoanIndividualMonitoringAccount.getInstance(accountNumber,group,principalAmount,childAccountsCount,
isAcceptingChild,loanStatus,applicationId);
this.glimAccountRepository.save(glimAccountInfo );
}
@Override
public void setIsAcceptingChild(GroupLoanIndividualMonitoringAccount glimAccount)
{
glimAccount.setIsAcceptingChild(true);
glimAccountRepository.save(glimAccount);
}
@Override
public void resetIsAcceptingChild(GroupLoanIndividualMonitoringAccount glimAccount)
{
glimAccount.setIsAcceptingChild(false);
glimAccountRepository.save(glimAccount);
}
@Override
public void incrementChildAccountCount(GroupLoanIndividualMonitoringAccount glimAccount)
{
long count=glimAccount.getChildAccountsCount();
glimAccount.setChildAccountsCount(count+1);
glimAccountRepository.save(glimAccount);
}
}
@@ -36,4 +36,10 @@ public interface LoanApplicationWritePlatformService {
CommandProcessingResult rejectApplication(Long loanId, JsonCommand command);
CommandProcessingResult applicantWithdrawsFromApplication(Long loanId, JsonCommand command);
CommandProcessingResult approveGLIMLoanAppication(Long loanId, JsonCommand command);
CommandProcessingResult undoGLIMLoanApplicationApproval(Long loanId, JsonCommand command);
CommandProcessingResult rejectGLIMApplicationApproval(Long loanId, JsonCommand command);
}
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.loanaccount.service;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
@@ -87,11 +88,14 @@ import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService
import org.apache.fineract.portfolio.fund.domain.Fund;
import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper;
import org.apache.fineract.portfolio.group.exception.GroupMemberNotFoundInGSIMException;
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
import org.apache.fineract.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
import org.apache.fineract.portfolio.loanaccount.domain.GLIMAccountInfoRepository;
import org.apache.fineract.portfolio.loanaccount.domain.GroupLoanIndividualMonitoringAccount;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
@@ -99,6 +103,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachin
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper;
@@ -115,6 +120,7 @@ import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationCo
import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationTransitionApiJsonValidator;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
import org.apache.fineract.portfolio.loanproduct.data.LoanProductData;
//import org.apache.fineract.portfolio.loanproduct.domain.*;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
@@ -127,8 +133,10 @@ import org.apache.fineract.portfolio.loanproduct.service.LoanProductReadPlatform
import org.apache.fineract.portfolio.note.domain.Note;
import org.apache.fineract.portfolio.note.domain.NoteRepository;
import org.apache.fineract.portfolio.rate.service.RateAssembler;
import org.apache.fineract.portfolio.savings.data.GroupSavingsIndividualMonitoringAccountData;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
import org.apache.fineract.portfolio.savings.service.GSIMReadPlatformService;
import org.apache.fineract.useradministration.domain.AppUser;
import org.joda.time.LocalDate;
import org.slf4j.Logger;
@@ -139,6 +147,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@Service
public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements LoanApplicationWritePlatformService {
@@ -179,7 +188,12 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
private final FineractEntityToEntityMappingRepository repository;
private final FineractEntityRelationRepository fineractEntityRelationRepository;
private final LoanProductReadPlatformService loanProductReadPlatformService;
private final RateAssembler rateAssembler;
private final GLIMAccountInfoWritePlatformService glimAccountInfoWritePlatformService;
private final GLIMAccountInfoRepository glimRepository;
private final LoanRepository loanRepository;
private final GSIMReadPlatformService gsimReadPlatformService;
@Autowired
public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
@@ -202,8 +216,12 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
final LoanScheduleAssembler loanScheduleAssembler, final LoanUtilService loanUtilService,
final CalendarReadPlatformService calendarReadPlatformService, final GlobalConfigurationRepositoryWrapper globalConfigurationRepository,
final FineractEntityToEntityMappingRepository repository, final FineractEntityRelationRepository fineractEntityRelationRepository,
final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService, final LoanProductReadPlatformService loanProductReadPlatformService,
final RateAssembler rateAssembler) {
final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService,
final GLIMAccountInfoWritePlatformService glimAccountInfoWritePlatformService,
final GLIMAccountInfoRepository glimRepository,final LoanRepository loanRepository,
final GSIMReadPlatformService gsimReadPlatformService, final RateAssembler rateAssembler,
final LoanProductReadPlatformService loanProductReadPlatformService
) {
this.context = context;
this.fromJsonHelper = fromJsonHelper;
this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator;
@@ -240,6 +258,10 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
this.fineractEntityRelationRepository = fineractEntityRelationRepository;
this.loanProductReadPlatformService = loanProductReadPlatformService;
this.rateAssembler = rateAssembler;
this.glimAccountInfoWritePlatformService=glimAccountInfoWritePlatformService;
this.glimRepository=glimRepository;
this.loanRepository=loanRepository;
this.gsimReadPlatformService=gsimReadPlatformService;
}
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
@@ -365,11 +387,106 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
createAndPersistCalendarInstanceForInterestRecalculation(newLoanApplication);
}
// loan account number generation
String accountNumber="";
GroupLoanIndividualMonitoringAccount glimAccount;
BigDecimal applicationId=BigDecimal.ZERO;
Boolean isLastChildApplication=false;
if (newLoanApplication.isAccountNumberRequiresAutoGeneration()) {
final AccountNumberFormat accountNumberFormat = this.accountNumberFormatRepository
.findByAccountType(EntityAccountType.LOAN);
newLoanApplication.updateAccountNo(this.accountNumberGenerator.generate(newLoanApplication, accountNumberFormat));
this.loanRepositoryWrapper.save(newLoanApplication);
final AccountNumberFormat accountNumberFormat = this.accountNumberFormatRepository.findByAccountType(EntityAccountType.LOAN);
// if application is of GLIM type
if(newLoanApplication.getLoanType()==4)
{
Group group= this.groupRepository.findOneWithNotFoundDetection(groupId);
//GLIM specific parameters
if(command.bigDecimalValueOfParameterNamedDefaultToNullIfZero("applicationId")!=null)
{
applicationId=command.bigDecimalValueOfParameterNamedDefaultToNullIfZero("applicationId");
}
if(command.booleanObjectValueOfParameterNamed("lastApplication")!=null)
{
isLastChildApplication=command.booleanPrimitiveValueOfParameterNamed("lastApplication");
}
if(command.booleanObjectValueOfParameterNamed("isParentAccount")!=null)
{
//empty table check
if(glimRepository.count()!=0)
{
//**************Parent-Not an empty table********************
accountNumber=this.accountNumberGenerator.generate(newLoanApplication, accountNumberFormat);
newLoanApplication.updateAccountNo(accountNumber+"1");
glimAccountInfoWritePlatformService.addGLIMAccountInfo(accountNumber,group, command.bigDecimalValueOfParameterNamedDefaultToNullIfZero("totalLoan"),Long.valueOf(1),true,
LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue(),applicationId);
newLoanApplication.setGlim(glimRepository.findOneByAccountNumber(accountNumber));
this.loanRepositoryWrapper.save(newLoanApplication);
}
else
{
//************** Parent-empty table********************
accountNumber=this.accountNumberGenerator.generate(newLoanApplication, accountNumberFormat);
newLoanApplication.updateAccountNo(accountNumber+"1");
glimAccountInfoWritePlatformService.addGLIMAccountInfo(accountNumber,group, command.bigDecimalValueOfParameterNamedDefaultToNullIfZero("totalLoan"),Long.valueOf(1),true,
LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue(),applicationId);
newLoanApplication.setGlim(glimRepository.findOneByAccountNumber(accountNumber));
this.loanRepositoryWrapper.save(newLoanApplication);
}
}
else
{
if(glimRepository.count()!=0)
{
// Child-Not an empty table
glimAccount=glimRepository.findOneByIsAcceptingChildAndApplicationId(true,applicationId);
accountNumber=glimAccount.getAccountNumber()+(glimAccount.getChildAccountsCount()+1);
newLoanApplication.updateAccountNo(accountNumber);
this.glimAccountInfoWritePlatformService.incrementChildAccountCount(glimAccount);
newLoanApplication.setGlim(glimAccount);
this.loanRepositoryWrapper.save(newLoanApplication);
}
else
{
//**************Child-empty table********************
// if the glim info is empty set the current account as parent
accountNumber=this.accountNumberGenerator.generate(newLoanApplication, accountNumberFormat);
newLoanApplication.updateAccountNo(accountNumber+"1");
glimAccountInfoWritePlatformService.addGLIMAccountInfo(accountNumber,group, command.bigDecimalValueOfParameterNamedDefaultToNullIfZero("totalLoan"),Long.valueOf(1),true,
LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue(),applicationId);
newLoanApplication.setGlim(glimRepository.findOneByAccountNumber(accountNumber));
this.loanRepositoryWrapper.save(newLoanApplication);
}
// reset in cases of last child application of glim
if(isLastChildApplication)
{
this.glimAccountInfoWritePlatformService.resetIsAcceptingChild(glimRepository.findOneByIsAcceptingChildAndApplicationId(true,applicationId));
}
}
}
else // for applications other than GLIM
{
newLoanApplication.updateAccountNo(this.accountNumberGenerator.generate(newLoanApplication, accountNumberFormat));
this.loanRepositoryWrapper.save(newLoanApplication);
}
}
final String submittedOnNote = command.stringValueOfParameterNamed("submittedOnNote");
@@ -411,17 +528,53 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
}
}
// Save linked account information
// Save linked account information
SavingsAccount savingsAccount;
AccountAssociations accountAssociations;
final Long savingsAccountId = command.longValueOfParameterNamed("linkAccountId");
if (savingsAccountId != null) {
final SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsAccountId);
this.fromApiJsonDeserializer.validatelinkedSavingsAccount(savingsAccount, newLoanApplication);
boolean isActive = true;
final AccountAssociations accountAssociations = AccountAssociations.associateSavingsAccount(newLoanApplication,
savingsAccount, AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION.getValue(), isActive);
this.accountAssociationsRepository.save(accountAssociations);
}
if(newLoanApplication.getLoanType()==4)
{
List<GroupSavingsIndividualMonitoringAccountData> childSavings= (List<GroupSavingsIndividualMonitoringAccountData>)gsimReadPlatformService.findGSIMAccountsByGSIMId(savingsAccountId);
//List<SavingsAccountSummaryData> childSavings=gsimAccount.getChildGSIMAccounts();
List<BigDecimal> gsimClientMembers=new ArrayList<BigDecimal>();
Map<BigDecimal,BigDecimal> clientAccountMappings=new HashMap<>();
for(GroupSavingsIndividualMonitoringAccountData childSaving:childSavings)
{
gsimClientMembers.add(childSaving.getClientId());
clientAccountMappings.put(childSaving.getClientId(), childSaving.getChildAccountId());
}
if(gsimClientMembers.contains(BigDecimal.valueOf(newLoanApplication.getClientId())))
{
savingsAccount = this.savingsAccountAssembler.assembleFrom((clientAccountMappings.get(BigDecimal.valueOf(newLoanApplication.getClientId()))).longValue());
this.fromApiJsonDeserializer.validatelinkedSavingsAccount(savingsAccount, newLoanApplication);
boolean isActive = true;
accountAssociations = AccountAssociations.associateSavingsAccount(newLoanApplication,
savingsAccount, AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION.getValue(), isActive);
this.accountAssociationsRepository.save(accountAssociations);
}else
{
throw new GroupMemberNotFoundInGSIMException(newLoanApplication.getClientId());
}
}
else
{
savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsAccountId);
this.fromApiJsonDeserializer.validatelinkedSavingsAccount(savingsAccount, newLoanApplication);
boolean isActive = true;
accountAssociations = AccountAssociations.associateSavingsAccount(newLoanApplication,
savingsAccount, AccountAssociationType.LINKED_ACCOUNT_ASSOCIATION.getValue(), isActive);
this.accountAssociationsRepository.save(accountAssociations);
}
}
if(command.parameterExists(LoanApiConstants.datatables)){
this.entityDatatableChecksWritePlatformService.saveDatatables(StatusEnum.CREATE.getCode().longValue(),
EntityTables.LOAN.getName(), newLoanApplication.getId(), newLoanApplication.productId(),
@@ -441,7 +594,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
.withOfficeId(newLoanApplication.getOfficeId()) //
.withClientId(newLoanApplication.getClientId()) //
.withGroupId(newLoanApplication.getGroupId()) //
.withLoanId(newLoanApplication.getId()) //
.withLoanId(newLoanApplication.getId())
.withGlimId(newLoanApplication.getGlimId())
.build();
} catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
@@ -1131,6 +1285,60 @@ public void checkForProductMixRestrictions(final Loan loan) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
@Transactional
@Override
public CommandProcessingResult approveGLIMLoanAppication(final Long loanId, final JsonCommand command)
{
final Long parentLoanId=loanId;
GroupLoanIndividualMonitoringAccount parentLoan=glimRepository.findById(parentLoanId).get();
JsonArray approvalFormData=command.arrayOfParameterNamed("approvalFormData");
JsonObject jsonObject=null;
JsonCommand childCommand=null;
Long[] childLoanId=new Long[approvalFormData.size()];
BigDecimal parentPrincipalAmount=command.bigDecimalValueOfParameterNamed("glimPrincipal");
for (int i = 0; i < approvalFormData.size(); i++) {
jsonObject=approvalFormData.get(i).getAsJsonObject();
childLoanId[i]=jsonObject.get("loanId").getAsLong();
}
CommandProcessingResult result=null;
int count=0,j=0;
for(JsonElement approvals:approvalFormData)
{
childCommand=JsonCommand.fromExistingCommand(command,approvals);
result=approveApplication(childLoanId[j++],childCommand);
if(result.getLoanId()!=null)
{
count++;
// if all the child loans are approved, mark the parent loan as approved
if(count==parentLoan.getChildAccountsCount())
{
parentLoan.setPrincipalAmount(parentPrincipalAmount);
parentLoan.setLoanStatus(LoanStatus.APPROVED.getValue());
glimRepository.save(parentLoan);
}
}
}
return result;
}
@Transactional
@Override
public CommandProcessingResult approveApplication(final Long loanId, final JsonCommand command) {
@@ -1177,6 +1385,8 @@ public void checkForProductMixRestrictions(final Loan loan) {
final Map<String, Object> changes = loan.loanApplicationApproval(currentUser, command, disbursementDataArray,
defaultLoanLifecycleStateMachine());
entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(),
StatusEnum.APPROVE.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
@@ -1239,6 +1449,42 @@ public void checkForProductMixRestrictions(final Loan loan) {
.build();
}
@Transactional
@Override
public CommandProcessingResult undoGLIMLoanApplicationApproval(final Long loanId, final JsonCommand command)
{
//GroupLoanIndividualMonitoringAccount glimAccount=glimRepository.findOne(loanId);
final Long parentLoanId=loanId;
GroupLoanIndividualMonitoringAccount parentLoan=glimRepository.findById(parentLoanId).get();
List<Loan> childLoans=this.loanRepository.findByGlimId(loanId);
CommandProcessingResult result=null;
int count=0;
for(Loan loan:childLoans)
{
result=undoApplicationApproval(loan.getId(),command);
if(result.getLoanId()!=null)
{
count++;
// if all the child loans are approved, mark the parent loan as approved
if(count==parentLoan.getChildAccountsCount())
{
parentLoan.setLoanStatus(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue());
glimRepository.save(parentLoan);
}
}
}
return result;
}
@Transactional
@Override
public CommandProcessingResult undoApplicationApproval(final Long loanId, final JsonCommand command) {
@@ -1285,6 +1531,41 @@ public void checkForProductMixRestrictions(final Loan loan) {
.build();
}
@Transactional
@Override
public CommandProcessingResult rejectGLIMApplicationApproval(final Long glimId, final JsonCommand command)
{
//GroupLoanIndividualMonitoringAccount glimAccount=glimRepository.findOne(loanId);
final Long parentLoanId=glimId;
GroupLoanIndividualMonitoringAccount parentLoan=glimRepository.findById(parentLoanId).get();
List<Loan> childLoans=this.loanRepository.findByGlimId(glimId);
CommandProcessingResult result=null;
int count=0;
for(Loan loan:childLoans)
{
result=rejectApplication(loan.getId(),command);
if(result.getLoanId()!=null)
{
count++;
// if all the child loans are Rejected, mark the parent loan as rejected
if(count==parentLoan.getChildAccountsCount())
{
parentLoan.setLoanStatus(LoanStatus.REJECTED.getValue());
glimRepository.save(parentLoan);
}
}
}
return result;
}
@Transactional
@Override
public CommandProcessingResult rejectApplication(final Long loanId, final JsonCommand command) {
@@ -148,6 +148,7 @@ public class LoanAssembler {
return loanAccount;
}
public void setHelpers(final Loan loanAccount) {
loanAccount.setHelpers(defaultLoanLifecycleStateMachine(), this.loanSummaryWrapper,
this.loanRepaymentScheduleTransactionProcessorFactory);
@@ -133,7 +133,6 @@ public interface LoanReadPlatformService {
LoanTransactionData retrieveLoanForeclosureTemplate(final Long loanId, final LocalDate transactionDate);
LoanAccountData retrieveLoanByLoanAccount(String loanAccountNumber);
Long retrieveLoanIdByAccountNumber(String loanAccountNumber);
@@ -142,4 +141,6 @@ public interface LoanReadPlatformService {
Integer retrieveNumberOfActiveLoans();
List<LoanAccountData> retrieveGLIMChildLoansByGLIMParentAccount(String parentloanAccountNumber);
}
@@ -233,6 +233,23 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
}
@Override
public List<LoanAccountData> retrieveGLIMChildLoansByGLIMParentAccount(String parentloanAccountNumber)
{
//final AppUser currentUser = this.context.authenticatedUser();
this.context.authenticatedUser();
final LoanMapper rm = new LoanMapper();
String sql="select "+rm.loanSchema()+" left join glim_parent_child_mapping as glim on glim.glim_child_account_id=l.account_no "+
"where glim.glim_parent_account_id=?";
return this.jdbcTemplate.query(sql, rm, new Object[] { parentloanAccountNumber });
}
@Override
public LoanScheduleData retrieveRepaymentSchedule(final Long loanId,
final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData, Collection<DisbursementData> disbursementData,
@@ -108,4 +108,10 @@ public interface LoanWritePlatformService {
CommandProcessingResult forecloseLoan(final Long loanId, JsonCommand command);
CommandProcessingResult disburseGLIMLoan(Long loanId, JsonCommand command);
CommandProcessingResult undoGLIMLoanDisbursal(Long loanId, JsonCommand command);
CommandProcessingResult makeGLIMLoanRepayment(Long loanId, JsonCommand command);
}
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.loanaccount.service;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
@@ -127,6 +128,8 @@ import org.apache.fineract.portfolio.loanaccount.data.LoanInstallmentChargeData;
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
import org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail;
import org.apache.fineract.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
import org.apache.fineract.portfolio.loanaccount.domain.GLIMAccountInfoRepository;
import org.apache.fineract.portfolio.loanaccount.domain.GroupLoanIndividualMonitoringAccount;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService;
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
@@ -140,6 +143,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanOverdueInstallmentCh
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.apache.fineract.portfolio.loanaccount.domain.LoanSubStatus;
@@ -191,6 +195,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatformService {
@@ -234,6 +239,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy;
private final CodeValueRepositoryWrapper codeValueRepository;
private final CashierTransactionDataValidator cashierTransactionDataValidator;
private final GLIMAccountInfoRepository glimRepository;
private final LoanRepository loanRepository;
@Autowired
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -264,7 +271,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy,
final CodeValueRepositoryWrapper codeValueRepository,
final LoanRepositoryWrapper loanRepositoryWrapper,
final CashierTransactionDataValidator cashierTransactionDataValidator) {
final CashierTransactionDataValidator cashierTransactionDataValidator,
final GLIMAccountInfoRepository glimRepository,
final LoanRepository loanRepository
) {
this.context = context;
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
this.loanAssembler = loanAssembler;
@@ -303,6 +313,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService;
this.codeValueRepository = codeValueRepository;
this.cashierTransactionDataValidator = cashierTransactionDataValidator;
this.loanRepository=loanRepository;
this.glimRepository=glimRepository;
}
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
@@ -310,6 +322,32 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
return new DefaultLoanLifecycleStateMachine(allowedLoanStatuses);
}
@Transactional
@Override
public CommandProcessingResult disburseGLIMLoan(final Long loanId, final JsonCommand command)
{
final Long parentLoanId=loanId;
GroupLoanIndividualMonitoringAccount parentLoan=glimRepository.findById(parentLoanId).get();
List<Loan> childLoans=this.loanRepository.findByGlimId(loanId);
CommandProcessingResult result=null;
int count=0;
for(Loan loan:childLoans)
{
result=disburseLoan(loan.getId(),command,false);
if(result.getLoanId()!=null)
{
count++;
// if all the child loans are approved, mark the parent loan as approved
if(count==parentLoan.getChildAccountsCount())
{
parentLoan.setLoanStatus(LoanStatus.ACTIVE.getValue());
glimRepository.save(parentLoan);
}
}
}
return result;
}
@Transactional
@Override
public CommandProcessingResult disburseLoan(final Long loanId, final JsonCommand command, Boolean isAccountTransfer) {
@@ -729,18 +767,44 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
return changes;
}
@Transactional
@Override
public CommandProcessingResult undoGLIMLoanDisbursal(final Long loanId, final JsonCommand command)
{
//GroupLoanIndividualMonitoringAccount glimAccount=glimRepository.findOne(loanId);
final Long parentLoanId=loanId;
GroupLoanIndividualMonitoringAccount parentLoan=glimRepository.findById(parentLoanId).get();
List<Loan> childLoans=this.loanRepository.findByGlimId(loanId);
CommandProcessingResult result=null;
int count=0;
for(Loan loan:childLoans)
{
result=undoLoanDisbursal(loan.getId(),command);
if(result.getLoanId()!=null)
{
count++;
// if all the child loans are approved, mark the parent loan as approved
if(count==parentLoan.getChildAccountsCount())
{
parentLoan.setLoanStatus(LoanStatus.APPROVED.getValue());
glimRepository.save(parentLoan);
}
}
}
return result;
}
@Transactional
@Override
public CommandProcessingResult undoLoanDisbursal(final Long loanId, final JsonCommand command) {
final AppUser currentUser = getAppUserIfPresent();
final Loan loan = this.loanAssembler.assembleFrom(loanId);
checkClientOrGroupActive(loan);
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_UNDO_DISBURSAL,
constructEntityMap(BUSINESS_ENTITY.LOAN, loan));
removeLoanCycle(loan);
final List<Long> existingTransactionIds = new ArrayList<>();
final List<Long> existingReversedTransactionIds = new ArrayList<>();
//
@@ -784,6 +848,36 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
.build();
}
@Transactional
@Override
public CommandProcessingResult makeGLIMLoanRepayment(final Long loanId, final JsonCommand command)
{
final Long parentLoanId=loanId;
GroupLoanIndividualMonitoringAccount parentLoan=glimRepository.findById(parentLoanId).get();
JsonArray repayments= command.arrayOfParameterNamed("formDataArray");
JsonCommand childCommand=null;
CommandProcessingResult result=null;
JsonObject jsonObject=null;
Long[] childLoanId=new Long[repayments.size()];
for (int i = 0; i < repayments.size(); i++) {
jsonObject=repayments.get(i).getAsJsonObject();
LOG.info("{}",jsonObject.toString());
childLoanId[i]=jsonObject.get("loanId").getAsLong();
}
int j=0;
for(JsonElement element:repayments )
{
childCommand=JsonCommand.fromExistingCommand(command,element);
result=makeLoanRepayment(childLoanId[j++],childCommand,false);
}
return result;
}
@Transactional
@Override
public CommandProcessingResult makeLoanRepayment(final Long loanId, final JsonCommand command, final boolean isRecoveryRepayment) {
@@ -3020,4 +3114,4 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
}
}
}
@@ -18,7 +18,7 @@
*/
package org.apache.fineract.portfolio.savings;
public class SavingsApiConstants {
public class SavingsApiConstants {
public static final String SAVINGS_PRODUCT_RESOURCE_NAME = "savingsproduct";
public static final String SAVINGS_ACCOUNT_RESOURCE_NAME = "savingsaccount";
@@ -72,11 +72,20 @@ public class SavingsApiConstants {
// savings product and account parameters
public static final String idParamName = "id";
public static final String isGSIM="isGSIM";
public static final String isParentAccount="isParentAccount";
public static final String accountNoParamName = "accountNo";
public static final String externalIdParamName = "externalId";
public static final String statusParamName = "status";
public static final String subStatusParamName = "subStatus";
public static final String clientIdParamName = "clientId";
public static final String isRetailAccountParamName = "isRetailAccount";
public static final String autogenerateTransactionIdParamName="autogenerateTransactionId";
public static final String transactionUpperLimitParamName="transactionUpperLimit";
public static final String transactionLowerLimitParamName="transactionLowerLimit";
public static final String retailEntriesParamName="retailEntries";
public static final String childAccountIdParamName="childAccountId";
public static final String groupIdParamName = "groupId";
public static final String productIdParamName = "productId";
public static final String fieldOfficerIdParamName = "fieldOfficerId";
@@ -178,5 +187,7 @@ public class SavingsApiConstants {
public static final String datatables = "datatables";
public static final String gsimApplicationId = "applicationId";
public static final String gsimLastApplication = "lastApplication";
public static final String ERROR_MSG_SAVINGS_ACCOUNT_NOT_ACTIVE = "not.in.active.state";
}
@@ -137,6 +137,11 @@ public class SavingsAccountTransactionsApiResource {
if (is(commandParam, "deposit")) {
final CommandWrapper commandRequest = builder.savingsAccountDeposit(savingsId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
}
else if(is(commandParam, "gsimDeposit"))
{
final CommandWrapper commandRequest = builder.gsimSavingsAccountDeposit(savingsId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "withdrawal")) {
final CommandWrapper commandRequest = builder.savingsAccountWithdrawal(savingsId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
@@ -170,6 +170,19 @@ public class SavingsAccountsApiResource {
return this.toApiJsonSerializer.serialize(result);
}
@POST
@Path("/gsim")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String submitGSIMApplication(final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().createGSIMAccount().withJson(apiRequestBodyAsJson).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@GET
@Path("{accountId}")
@Consumes({ MediaType.APPLICATION_JSON })
@@ -265,6 +278,83 @@ public class SavingsAccountsApiResource {
return this.toApiJsonSerializer.serialize(result);
}
@PUT
@Path("/gsim/{parentAccountId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
/* public String updateGsim(@PathParam("parentAccountId") final Long parentAccountId, final String apiRequestBodyAsJson,
@QueryParam("command") final String commandParam) {*/
public String updateGsim(@PathParam("parentAccountId") final Long parentAccountId, final String apiRequestBodyAsJson)
{
/* if (is(commandParam, "updateWithHoldTax")) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson).updateWithHoldTax(accountId)
.build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}*/
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateGSIMAccount(parentAccountId).withJson(apiRequestBodyAsJson)
.build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@POST
@Path("/gsimcommands/{parentAccountId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String handleGSIMCommands(@PathParam("parentAccountId") final Long parentAccountId, @QueryParam("command") final String commandParam,
final String apiRequestBodyAsJson) {
String jsonApiRequest = apiRequestBodyAsJson;
if (StringUtils.isBlank(jsonApiRequest)) {
jsonApiRequest = "{}";
}
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(jsonApiRequest);
CommandProcessingResult result = null;
if (is(commandParam, "reject")) {
final CommandWrapper commandRequest = builder.rejectGSIMAccountApplication(parentAccountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "withdrawnByApplicant")) {
final CommandWrapper commandRequest = builder.withdrawSavingsAccountApplication(parentAccountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "approve")) {
final CommandWrapper commandRequest = builder.approveGSIMAccountApplication(parentAccountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "undoapproval")) {
final CommandWrapper commandRequest = builder.undoGSIMApplicationApproval(parentAccountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "activate")) {
final CommandWrapper commandRequest = builder.gsimAccountActivation(parentAccountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "calculateInterest")) {
final CommandWrapper commandRequest = builder.withNoJsonBody().savingsAccountInterestCalculation(parentAccountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "postInterest")) {
final CommandWrapper commandRequest = builder.savingsAccountInterestPosting(parentAccountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "applyAnnualFees")) {
final CommandWrapper commandRequest = builder.savingsAccountApplyAnnualFees(parentAccountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "close")) {
final CommandWrapper commandRequest = builder.closeGSIMApplication(parentAccountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
}
if (result == null) {
throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "reject", "withdrawnByApplicant", "approve",
"undoapproval", "activate", "calculateInterest", "postInterest", "close", "assignSavingsOfficer",
"unassignSavingsOfficer", SavingsApiConstants.COMMAND_BLOCK_DEBIT, SavingsApiConstants.COMMAND_UNBLOCK_DEBIT,
SavingsApiConstants.COMMAND_BLOCK_CREDIT, SavingsApiConstants.COMMAND_UNBLOCK_CREDIT,
SavingsApiConstants.COMMAND_BLOCK_ACCOUNT, SavingsApiConstants.COMMAND_UNBLOCK_ACCOUNT });
}
return this.toApiJsonSerializer.serialize(result);
}
@POST
@Path("{accountId}")
@Consumes({ MediaType.APPLICATION_JSON })
@@ -0,0 +1,75 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.savings.data;
import java.math.BigDecimal;
import java.util.List;
import org.apache.fineract.portfolio.accountdetails.data.SavingsSummaryCustom;
public class GSIMContainer {
private final BigDecimal gsimId;
private final BigDecimal groupId;
private final String accountNumber;
private final List<SavingsSummaryCustom> childGSIMAccounts;
private final BigDecimal parentBalance;
private final String savingsStatus;
public GSIMContainer(final BigDecimal gsimId, final BigDecimal groupId, final String accountNumber,
final List<SavingsSummaryCustom> childGSIMAccounts, final BigDecimal parentBalance,
final String savingsStatus) {
this.gsimId = gsimId;
this.groupId = groupId;
this.accountNumber = accountNumber;
this.childGSIMAccounts = childGSIMAccounts;
this.parentBalance = parentBalance;
this.savingsStatus = savingsStatus;
}
public BigDecimal getGsimId() {
return gsimId;
}
public BigDecimal getGroupId() {
return groupId;
}
public String getAccountNumber() {
return accountNumber;
}
public List<SavingsSummaryCustom> getChildGSIMAccounts() {
return childGSIMAccounts;
}
public BigDecimal getparentBalance() {
return parentBalance;
}
public String getSavingsStatus() {
return savingsStatus;
}
}
@@ -0,0 +1,125 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.savings.data;
import java.math.BigDecimal;
public class GroupSavingsIndividualMonitoringAccountData
{
private final BigDecimal gsimId;
private final BigDecimal groupId;
private final BigDecimal clientId;
private final String accountNumber;
private final BigDecimal childAccountId;
private final String childAccountNumber;
private final BigDecimal childDeposit;
private final BigDecimal parentDeposit;
private final Long childAccountsCount;
private final String savingsStatus;
private GroupSavingsIndividualMonitoringAccountData(final BigDecimal glimId,final BigDecimal groupId,final BigDecimal clientId,final String accountNumber,final BigDecimal childAccountId, final String childAccountNumber,
final BigDecimal childDeposit, final BigDecimal parentDeposit,
final Long childAccountsCount,final String savingsStatus) {
this.gsimId=glimId;
this.groupId=groupId;
this.clientId=clientId;
this.accountNumber = accountNumber;
this.childAccountId=childAccountId;
this.childAccountNumber = childAccountNumber;
this.childDeposit = childDeposit;
this.parentDeposit = parentDeposit;
this.childAccountsCount = childAccountsCount;
this.savingsStatus=savingsStatus;
}
public static GroupSavingsIndividualMonitoringAccountData getInstance(final BigDecimal glimId, final BigDecimal groupId,final String accountNumber, final String childAccountNumber,
final BigDecimal childDeposit, final BigDecimal parentDeposit,
final Long childAccountsCount,final String savingsStatus)
{
return new GroupSavingsIndividualMonitoringAccountData(glimId,groupId,null,accountNumber,null,childAccountNumber,
childDeposit,parentDeposit,childAccountsCount,savingsStatus);
}
public static GroupSavingsIndividualMonitoringAccountData getInstance1(final BigDecimal glimId,final BigDecimal groupId,final String accountNumber,
final BigDecimal parentDeposit,final String savingsStatus)
{
return new GroupSavingsIndividualMonitoringAccountData(glimId,groupId,null,accountNumber,null,null,null,parentDeposit,null,savingsStatus);
}
public static GroupSavingsIndividualMonitoringAccountData getInstance2(final BigDecimal glimId, final BigDecimal groupId,final BigDecimal clientId,final String accountNumber, final BigDecimal childAccountId,final String childAccountNumber,
final BigDecimal childDeposit, final BigDecimal parentDeposit,
final Long childAccountsCount,final String savingsStatus)
{
return new GroupSavingsIndividualMonitoringAccountData(glimId,groupId,clientId,accountNumber,childAccountId,childAccountNumber,
childDeposit,parentDeposit,childAccountsCount,savingsStatus);
}
public BigDecimal getGsimId() {
return gsimId;
}
public BigDecimal getGroupId() {
return groupId;
}
public BigDecimal getClientId() {
return clientId;
}
public String getAccountNumber() {
return accountNumber;
}
public BigDecimal getChildAccountId() {
return childAccountId;
}
public String getChildAccountNumber() {
return childAccountNumber;
}
public BigDecimal getChildDeposit() {
return childDeposit;
}
public BigDecimal getParentDeposit() {
return parentDeposit;
}
public Long getChildAccountsCount() {
return childAccountsCount;
}
public String getSavingsStatus() {
return savingsStatus;
}
}
@@ -31,7 +31,7 @@ public class SavingsAccountConstant extends SavingsApiConstants {
* parameters to match those of request parameters.
*/
protected static final Set<String> SAVINGS_ACCOUNT_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(
localeParamName, dateFormatParamName, monthDayFormatParamName, staffIdParamName, accountNoParamName,
localeParamName, dateFormatParamName, monthDayFormatParamName, staffIdParamName, isGSIM, isParentAccount,accountNoParamName,
externalIdParamName, clientIdParamName, groupIdParamName, productIdParamName, fieldOfficerIdParamName,
submittedOnDateParamName, nominalAnnualInterestRateParamName, interestCompoundingPeriodTypeParamName,
interestPostingPeriodTypeParamName, interestCalculationTypeParamName,
@@ -41,7 +41,8 @@ public class SavingsAccountConstant extends SavingsApiConstants {
withdrawalFeeForTransfersParamName, feeAmountParamName, feeOnMonthDayParamName, chargesParamName,
allowOverdraftParamName, overdraftLimitParamName, minRequiredBalanceParamName,
enforceMinRequiredBalanceParamName, nominalAnnualInterestRateOverdraftParamName,
minOverdraftForInterestCalculationParamName, withHoldTaxParamName, datatables));
minOverdraftForInterestCalculationParamName, withHoldTaxParamName, datatables, gsimApplicationId,
gsimLastApplication));
/**
* These parameters will match the class level parameters of
@@ -52,7 +53,8 @@ public class SavingsAccountConstant extends SavingsApiConstants {
protected static final Set<String> SAVINGS_ACCOUNT_TRANSACTION_REQUEST_DATA_PARAMETERS = new HashSet<>(
Arrays.asList(localeParamName, dateFormatParamName, transactionDateParamName, transactionAmountParamName,
paymentTypeIdParamName, transactionAccountNumberParamName, checkNumberParamName,
routingCodeParamName, receiptNumberParamName, bankNumberParamName, noteParamName));
routingCodeParamName, receiptNumberParamName, bankNumberParamName, retailEntriesParamName,
childAccountIdParamName, noteParamName));
protected static final Set<String> SAVINGS_ACCOUNT_TRANSACTION_RESPONSE_DATA_PARAMETERS = new HashSet<>(
Arrays.asList(idParamName, accountNoParamName));
@@ -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.savings.domain;
import java.math.BigDecimal;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface GSIMRepositoy extends JpaRepository<GroupSavingsIndividualMonitoring, Long>, JpaSpecificationExecutor<GroupSavingsIndividualMonitoring>
{
GroupSavingsIndividualMonitoring findOneByIsAcceptingChild(boolean acceptingChild);
GroupSavingsIndividualMonitoring findOneByIsAcceptingChildAndApplicationId(boolean acceptingChild,BigDecimal applicationId);
GroupSavingsIndividualMonitoring findOneByAccountNumber(String accountNumber);
}
@@ -0,0 +1,140 @@
/**
* 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.savings.domain;
import java.math.BigDecimal;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.portfolio.group.domain.Group;
@Entity
@Table(name = "gsim_accounts", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_number" }, name = "gsim_id")})
public class GroupSavingsIndividualMonitoring extends AbstractPersistableCustom
{
@ManyToOne
@JoinColumn(name = "group_id", nullable = false)
private Group group;
@Column(name = "account_number", nullable = false)
private String accountNumber;
@Column(name = "parent_deposit")
private BigDecimal parentDeposit;
@Column(name = "child_accounts_count")
private Long childAccountsCount;
@Column(name = "accepting_child")
private Boolean isAcceptingChild;
@OneToMany
private Set<SavingsAccount> childSaving;
@Column(name = "savings_status_id", nullable = false)
private Integer savingsStatus;
@Column(name = "application_id", nullable = true)
private BigDecimal applicationId;
private GroupSavingsIndividualMonitoring(String accountNumber,Group group,BigDecimal parentDeposit,Long childAccountsCount,
Boolean isAcceptingChild,Integer savingsStatus,BigDecimal applicationId)
{
this.accountNumber=accountNumber;
this.group=group;
this.parentDeposit=parentDeposit;
this.childAccountsCount=childAccountsCount;
this.isAcceptingChild=isAcceptingChild;
this.savingsStatus=savingsStatus;
this.applicationId=applicationId;
}
public static GroupSavingsIndividualMonitoring getInstance(String accountNumber,Group group,BigDecimal parentDeposit,Long childAccountsCount,
Boolean isAcceptingChild,Integer savingsStatus,BigDecimal applicationId)
{
return new GroupSavingsIndividualMonitoring(accountNumber,group,parentDeposit,childAccountsCount,
isAcceptingChild,savingsStatus,applicationId);
}
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
public String getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(String accountNumber) {
this.accountNumber = accountNumber;
}
public BigDecimal getParentDeposit() {
return parentDeposit;
}
public void setParentDeposit(BigDecimal parentDeposit) {
this.parentDeposit = parentDeposit;
}
public Long getChildAccountsCount() {
return childAccountsCount;
}
public void setChildAccountsCount(Long childAccountsCount) {
this.childAccountsCount = childAccountsCount;
}
public Boolean getIsAcceptingChild() {
return isAcceptingChild;
}
public void setIsAcceptingChild(Boolean isAcceptingChild) {
this.isAcceptingChild = isAcceptingChild;
}
public Set<SavingsAccount> getChildSaving() {
return childSaving;
}
public void setChildSaving(Set<SavingsAccount> childSaving) {
this.childSaving = childSaving;
}
public Integer getSavingsStatus() {
return savingsStatus;
}
public void setSavingsStatus(Integer savingsStatus) {
this.savingsStatus = savingsStatus;
}
}
@@ -140,10 +140,14 @@ public class SavingsAccount extends AbstractPersistableCustom {
@JoinColumn(name = "client_id", nullable = true)
protected Client client;
@ManyToOne(optional = true)
@ManyToOne(optional = true, fetch=FetchType.LAZY)
@JoinColumn(name = "group_id", nullable = true)
protected Group group;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name = "gsim_id", nullable = true)
private GroupSavingsIndividualMonitoring gsim;
@ManyToOne
@JoinColumn(name = "product_id", nullable = false)
protected SavingsProduct product;
@@ -1612,7 +1616,15 @@ public class SavingsAccount extends AbstractPersistableCustom {
return id;
}
public Long hasSavingsOfficerId() {
public GroupSavingsIndividualMonitoring getGsim() {
return gsim;
}
public void setGsim(GroupSavingsIndividualMonitoring gsim) {
this.gsim = gsim;
}
public Long hasSavingsOfficerId() {
Long id = null;
if (this.savingsOfficer != null) {
id = this.savingsOfficer.getId();
@@ -2691,10 +2703,6 @@ public class SavingsAccount extends AbstractPersistableCustom {
return getActivationLocalDate() == null ? getSubmittedOnLocalDate() : getActivationLocalDate();
}
public AccountType getAccountType() {
return AccountType.fromInt(accountType);
}
public DepositAccountType depositAccountType() {
return DepositAccountType.fromInt(depositType);
}
@@ -3137,8 +3145,19 @@ public class SavingsAccount extends AbstractPersistableCustom {
this.savingsOnHoldAmount = getSavingsHoldAmount().subtract(amount);
}
public AccountType getAccountType() {
return AccountType.fromInt(accountType);
}
public Integer getAccountTypes() {
return accountType;
}
public void setAccountType(Integer accountType) {
this.accountType = accountType;
}
private boolean isOverdraft() {
return allowOverdraft;
}
}
@@ -71,12 +71,15 @@ import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundException;
import org.apache.fineract.useradministration.domain.AppUser;
import org.joda.time.LocalDate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class SavingsAccountAssembler {
private final static Logger LOG = LoggerFactory.getLogger(SavingsAccountAssembler.class);
private final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper;
private final SavingsHelper savingsHelper;
private final ClientRepositoryWrapper clientRepository;
@@ -125,6 +128,8 @@ public class SavingsAccountAssembler {
Group group = null;
Staff fieldOfficer = null;
AccountType accountType = AccountType.INVALID;
final Long clientId = this.fromApiJsonHelper.extractLongNamed(clientIdParamName, element);
if (clientId != null) {
client = this.clientRepository.findOneWithNotFoundDetection(clientId);
@@ -147,6 +152,15 @@ public class SavingsAccountAssembler {
accountType = AccountType.JLG;
}
if((Boolean)command.booleanPrimitiveValueOfParameterNamed("isGSIM")!=null)
{
LOG.info("setting system to gsim");
if(command.booleanPrimitiveValueOfParameterNamed("isGSIM"))
{
accountType = AccountType.GSIM;
}
}
final Long fieldOfficerId = this.fromApiJsonHelper.extractLongNamed(fieldOfficerIdParamName, element);
if (fieldOfficerId != null) {
fieldOfficer = this.staffRepository.findOneWithNotFoundDetection(fieldOfficerId);
@@ -298,6 +312,7 @@ public class SavingsAccountAssembler {
return account;
}
public void setHelpers(final SavingsAccount account) {
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
}
@@ -36,4 +36,5 @@ public interface SavingsAccountDomainService {
void postJournalEntries(SavingsAccount savingsAccount, Set<Long> existingTransactionIds, Set<Long> existingReversedTransactionIds);
SavingsAccountTransaction handleDividendPayout(SavingsAccount account, LocalDate transactionDate, BigDecimal transactionAmount);
}
@@ -134,6 +134,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
return user;
}
@Transactional
@Override
public SavingsAccountTransaction handleDeposit(final SavingsAccount account, final DateTimeFormatter fmt,
@@ -176,7 +177,6 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate);
}
saveTransactionToGenerateTransactionId(deposit);
this.savingsAccountRepository.saveAndFlush(account);
@@ -32,6 +32,9 @@ public interface SavingsAccountRepository extends JpaRepository<SavingsAccount,
@Query("select s_acc from SavingsAccount s_acc where s_acc.client.id = :clientId")
List<SavingsAccount> findSavingAccountByClientId(@Param("clientId") Long clientId);
@Query("select s_acc from SavingsAccount s_acc where s_acc.gsim.id = :gsimId")
List<SavingsAccount> findSavingAccountByGsimId(@Param("gsimId") Long gsimId);
@Query("select s_acc from SavingsAccount s_acc where s_acc.status = :status")
List<SavingsAccount> findSavingAccountByStatus(@Param("status") Integer status);
@@ -102,6 +102,10 @@ public class SavingsAccountRepositoryWrapper {
return this.repository.findByGroupId(groupId) ;
}
public List<SavingsAccount> findByGsimId(@Param("gsimId") Long gsimId) {
return this.repository.findSavingAccountByGsimId(gsimId);
}
//Root Entity is enough
public SavingsAccount findNonClosedAccountByAccountNumber(@Param("accountNumber") String accountNumber) {
return this.repository.findNonClosedAccountByAccountNumber(accountNumber) ;
@@ -117,6 +117,10 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
@Column(name = "is_manual", length = 1, nullable = true)
private boolean isManualTransaction;
@Column(name = "is_loan_disbursement", length = 1, nullable = true)
private boolean isLoanDisbursement;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch=FetchType.EAGER)
@JoinColumn(name = "savings_transaction_id", referencedColumnName = "id", nullable = false)
private List<SavingsAccountTransactionTaxDetails> taxDetails = new ArrayList<>();
@@ -407,6 +411,10 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
return getTransactionLocalDate().isEqual(occursOnDate);
}
public void setLoanDisbursement(boolean isLoanDisbursement) {
this.isLoanDisbursement = isLoanDisbursement;
}
public void zeroBalanceFields() {
this.runningBalance = null;
this.cumulativeBalance = null;
@@ -0,0 +1,51 @@
/**
* 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.savings.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.savings.service.SavingsAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "GSIMACCOUNT", action = "CLOSE")
public class CloseGSIMCommandHandler implements NewCommandSourceHandler
{
private final SavingsAccountWritePlatformService writePlatformService;
@Autowired
public CloseGSIMCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) {
this.writePlatformService = savingAccountWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.bulkGSIMClose(command.getSavingsId(), command);
}
}
@@ -0,0 +1,48 @@
/**
* 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.savings.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.savings.service.SavingsAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "GSIMACCOUNT", action = "ACTIVATE")
public class GSIMAccountActivationCommandHandler implements NewCommandSourceHandler {
private final SavingsAccountWritePlatformService savingAccountWritePlatformService;
@Autowired
public GSIMAccountActivationCommandHandler(
final SavingsAccountWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.savingAccountWritePlatformService.gsimActivate(command.getSavingsId(),command);
}
}
@@ -0,0 +1,49 @@
/**
* 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.savings.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.savings.service.SavingsApplicationProcessWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "GSIMACCOUNT", action = "APPROVE")
public class GSIMApplicationApprovalCommandHandler implements NewCommandSourceHandler
{
private final SavingsApplicationProcessWritePlatformService savingAccountWritePlatformService;
@Autowired
public GSIMApplicationApprovalCommandHandler(
final SavingsApplicationProcessWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.savingAccountWritePlatformService.approveGSIMApplication(command.getSavingsId(),command);
}
}
@@ -0,0 +1,49 @@
/**
* 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.savings.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.savings.service.SavingsApplicationProcessWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "GSIMACCOUNT", action = "UPDATE")
public class GSIMApplicationModificationCommandHandler implements NewCommandSourceHandler
{
private final SavingsApplicationProcessWritePlatformService savingAccountWritePlatformService;
@Autowired
public GSIMApplicationModificationCommandHandler(
final SavingsApplicationProcessWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.savingAccountWritePlatformService.modifyGSIMApplication(command.entityId(), command);
}
}
@@ -0,0 +1,51 @@
/**
* 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.savings.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.savings.service.SavingsApplicationProcessWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "GSIMACCOUNT", action = "REJECT")
public class GSIMApplicationRejectionHandler implements NewCommandSourceHandler
{
private final SavingsApplicationProcessWritePlatformService savingAccountWritePlatformService;
@Autowired
public GSIMApplicationRejectionHandler(
final SavingsApplicationProcessWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.savingAccountWritePlatformService.rejectGSIMApplication(command.entityId(),command);
}
}
@@ -0,0 +1,49 @@
/**
* 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.savings.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.savings.service.SavingsApplicationProcessWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "GSIMACCOUNT", action = "CREATE")
public class GSIMApplicationSubmittalCommandHandler implements NewCommandSourceHandler
{
private final SavingsApplicationProcessWritePlatformService savingAccountWritePlatformService;
@Autowired
public GSIMApplicationSubmittalCommandHandler(
final SavingsApplicationProcessWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.savingAccountWritePlatformService.submitGSIMApplication(command);
}
}
@@ -0,0 +1,49 @@
/**
* 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.savings.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.savings.service.SavingsAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "GSIMACCOUNT", action = "DEPOSIT")
public class GSIMDepositCommandHandler implements NewCommandSourceHandler {
private final SavingsAccountWritePlatformService writePlatformService;
@Autowired
public GSIMDepositCommandHandler(final SavingsAccountWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.gsimDeposit(command.getSavingsId(), command);
}
}
@@ -0,0 +1,51 @@
/**
* 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.savings.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.savings.service.SavingsApplicationProcessWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "GSIMACCOUNT", action = "APPROVALUNDO")
public class GSIMUndoApprovalCommandHandler implements NewCommandSourceHandler
{
private final SavingsApplicationProcessWritePlatformService writePlatformService;
@Autowired
public GSIMUndoApprovalCommandHandler(final SavingsApplicationProcessWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.undoGSIMApplicationApproval(command.entityId(), command);
}
}
@@ -0,0 +1,48 @@
/**
* 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.savings.service;
import java.util.Collection;
import java.util.List;
import org.apache.fineract.portfolio.savings.data.GSIMContainer;
import org.apache.fineract.portfolio.savings.data.GroupSavingsIndividualMonitoringAccountData;
public interface GSIMReadPlatformService {
Collection<GroupSavingsIndividualMonitoringAccountData> findGsimAccountByParentAccountNumber(String parentAccountIds);
Collection<GroupSavingsIndividualMonitoringAccountData> findGSIMAccountsByGSIMId(Long glimId);
Collection<GroupSavingsIndividualMonitoringAccountData> findGSIMAccountsByGroupId(String groupId);
Collection<GSIMContainer> findGSIMAccountContainerByGroupId(Long groupId);
Collection<GSIMContainer> findGsimAccountContainerbyGsimAccountNumber(String accountNumber);
Collection<GroupSavingsIndividualMonitoringAccountData> findGsimAccountByGroupIdandAccountNo(String groupId,
String accountNo);
List<GSIMContainer> findGsimAccountContainerbyGsimAccountId(Long parentAccountId);
GroupSavingsIndividualMonitoringAccountData findGSIMAccountByGSIMId(Long gsimId);
}
@@ -0,0 +1,389 @@
/**
* 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.savings.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.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.portfolio.accountdetails.data.SavingsSummaryCustom;
import org.apache.fineract.portfolio.accountdetails.service.AccountEnumerations;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.apache.fineract.portfolio.savings.data.GSIMContainer;
import org.apache.fineract.portfolio.savings.data.GroupSavingsIndividualMonitoringAccountData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountApplicationTimelineData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountStatusEnumData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountSubStatusEnumData;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
@Service
public class GSIMReadPlatformServiceImpl implements GSIMReadPlatformService
{
private final JdbcTemplate jdbcTemplate;
private final PlatformSecurityContext context;
private final ColumnValidator columnValidator;
@Autowired
public GSIMReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource
,final ColumnValidator columnValidator) {
this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.columnValidator = columnValidator;
}
private static final class GSIMFieldsMapper implements RowMapper<GroupSavingsIndividualMonitoringAccountData> {
public String schema() {
return "gsim.id as gsimId,sv.group_id as groupId,sv.client_id as clientId,gsim.account_number as accountNumber, sv.id as childAccountId,sv.account_no as childAccountNumber,sv.account_balance_derived as childBalance,gsim.parent_deposit as parentBalance,gsim.child_accounts_count as childAccountsCount,"
+"gsim.savings_status_id as savingsStatus from gsim_accounts gsim,m_savings_account sv where gsim.id=sv.gsim_id";
}
@Override
public GroupSavingsIndividualMonitoringAccountData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum)
throws SQLException {
final BigDecimal gsimId=rs.getBigDecimal("gsimId");
final BigDecimal groupId=rs.getBigDecimal("groupId");
final BigDecimal clientId=rs.getBigDecimal("clientId");
final String accountNumber=rs.getString("accountNumber");
final BigDecimal childAccountId=rs.getBigDecimal("childAccountId");
final String childAccountNumber=rs.getString("childAccountNumber");
final Long childAccountsCount=rs.getLong("childAccountsCount");
final BigDecimal parentBalance=rs.getBigDecimal("parentBalance");
final BigDecimal childBalance=rs.getBigDecimal("childBalance");
final String savingsStatus=SavingsAccountStatusType.fromInt((int)rs.getLong("savingsStatus")).toString();
return GroupSavingsIndividualMonitoringAccountData.getInstance2(gsimId,groupId,clientId,accountNumber,childAccountId,childAccountNumber,parentBalance,childBalance,
childAccountsCount,savingsStatus);
}
}
private static final class GSIMMapper implements RowMapper<GroupSavingsIndividualMonitoringAccountData> {
public String schema() {
return "gsim.id as gsimId,gsim.group_id as groupId,gsim.account_number as accountNumber,gsim.parent_deposit as parentDeposit,gsim.child_accounts_count as childAccountsCount,"
+"gsim.savings_status_id as savingsStatus from gsim_accounts gsim";
}
@Override
public GroupSavingsIndividualMonitoringAccountData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum)
throws SQLException {
final BigDecimal glimId=rs.getBigDecimal("gsimId");
final BigDecimal groupId=rs.getBigDecimal("groupId");
final String accountNumber=rs.getString("accountNumber");
final BigDecimal parentDeposit=rs.getBigDecimal("parentDeposit");
final String loanStatus=LoanStatus.fromInt((int)rs.getLong("savingsStatus")).toString();
return GroupSavingsIndividualMonitoringAccountData.getInstance1(glimId,groupId, accountNumber, parentDeposit,loanStatus);
}
}
@Override
public Collection<GSIMContainer> findGSIMAccountContainerByGroupId(Long groupId) {
this.context.authenticatedUser();
Collection<GroupSavingsIndividualMonitoringAccountData> gsimInfo=findGSIMAccountsByGroupId(groupId+"");
//List<LoanAccountSummaryData> glimAccounts = retrieveLoanAccountDetails(loanWhereClauseForGroupAndLoanType, new Object[] { groupId });
String savingswhereClauseForGroup;
List<GSIMContainer> gsimAccounts=new ArrayList<GSIMContainer>();
List<SavingsSummaryCustom> childSavings;
for(GroupSavingsIndividualMonitoringAccountData gsimAccount:gsimInfo)
{
BigDecimal gsimId = gsimAccount.getGsimId();
savingswhereClauseForGroup = " where sa.group_id = ? and sa.gsim_id = ? order by sa.status_enum ASC, sa.account_no ASC";
childSavings=retrieveAccountDetails(savingswhereClauseForGroup,new Object[] { groupId , gsimId});
gsimAccounts.add(new GSIMContainer(gsimAccount.getGsimId(),gsimAccount.getGroupId(), gsimAccount.getAccountNumber(),
childSavings, gsimAccount.getParentDeposit(),gsimAccount.getSavingsStatus()));
}
return gsimAccounts;
}
@Override
public Collection<GSIMContainer> findGsimAccountContainerbyGsimAccountNumber(String accountNumber) {
this.context.authenticatedUser();
Collection<GroupSavingsIndividualMonitoringAccountData> gsimInfo=findGsimAccountByParentAccountNumber(accountNumber);
//List<LoanAccountSummaryData> glimAccounts = retrieveLoanAccountDetails(loanWhereClauseForGroupAndLoanType, new Object[] { groupId });
final String savingswhereClauseForGroup = " where gsim.account_number = ? order by sa.status_enum ASC, sa.account_no ASC";
List<GSIMContainer> gsimAccounts=new ArrayList<GSIMContainer>();
for(GroupSavingsIndividualMonitoringAccountData gsimAccount:gsimInfo)
{
List<SavingsSummaryCustom> childSavings=retrieveAccountDetails(savingswhereClauseForGroup,new Object[] { accountNumber });
gsimAccounts.add(new GSIMContainer(gsimAccount.getGsimId(),gsimAccount.getGroupId(), gsimAccount.getAccountNumber(),
childSavings, gsimAccount.getParentDeposit(),gsimAccount.getSavingsStatus()));
}
return gsimAccounts;
}
@Override
public List<GSIMContainer> findGsimAccountContainerbyGsimAccountId(Long parentAccountId) {
this.context.authenticatedUser();
GroupSavingsIndividualMonitoringAccountData gsimAccount=findGSIMAccountByGSIMId(parentAccountId);
//List<LoanAccountSummaryData> glimAccounts = retrieveLoanAccountDetails(loanWhereClauseForGroupAndLoanType, new Object[] { groupId });
final String savingswhereClauseForGroup = " where sa.gsim_id = ? order by sa.status_enum ASC, sa.account_no ASC";
List<SavingsSummaryCustom> childSavings=retrieveAccountDetails(savingswhereClauseForGroup,new Object[] { parentAccountId });
List<GSIMContainer> parentGsim=new ArrayList<GSIMContainer>();
parentGsim.add(new GSIMContainer(gsimAccount.getGsimId(),gsimAccount.getGroupId(), gsimAccount.getAccountNumber(),
childSavings, gsimAccount.getParentDeposit(),gsimAccount.getSavingsStatus()));
return parentGsim ;
}
@Override
public Collection<GroupSavingsIndividualMonitoringAccountData> findGSIMAccountsByGSIMId(final Long gsimId) {
this.context.authenticatedUser();
final GSIMFieldsMapper rm = new GSIMFieldsMapper();
final String sql = "select " + rm.schema() + " and gsim.id=?";
return this.jdbcTemplate.query(sql, rm, new Object[] { gsimId });
}
@Override
public GroupSavingsIndividualMonitoringAccountData findGSIMAccountByGSIMId(final Long gsimId) {
this.context.authenticatedUser();
final GSIMMapper rm = new GSIMMapper();
final String sql = "select " + rm.schema() + " where gsim.id=?";
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { gsimId });
}
@Override
public Collection<GroupSavingsIndividualMonitoringAccountData> findGSIMAccountsByGroupId(String groupId) {
this.context.authenticatedUser();
final GSIMMapper rm = new GSIMMapper();
final String sql = "select " + rm.schema() + " where gsim.group_id=?";
return this.jdbcTemplate.query(sql, rm, new Object[] { groupId });
}
@Override
public Collection<GroupSavingsIndividualMonitoringAccountData> findGsimAccountByParentAccountNumber(String parentAccountIds) {
this.context.authenticatedUser();
final GSIMMapper rm = new GSIMMapper();
final String sql = "select " + rm.schema() + " where gsim.account_number=?";
return this.jdbcTemplate.query(sql, rm, new Object[] { parentAccountIds });
}
@Override
public Collection<GroupSavingsIndividualMonitoringAccountData> findGsimAccountByGroupIdandAccountNo(String groupId,String accountNo) {
this.context.authenticatedUser();
GSIMMapper rm=new GSIMMapper();
final String sql="select "+rm.schema()+" where gsim.group_id=? and gsim.account_number=?";
return this.jdbcTemplate.query(sql, rm, new Object[] { accountNo });
}
private List<SavingsSummaryCustom> retrieveAccountDetails(final String savingswhereClause, final Object[] inputs) {
final SavingsAccountSummaryDataMapper savingsAccountSummaryDataMapper = new SavingsAccountSummaryDataMapper();
final String savingsSql = "select " + savingsAccountSummaryDataMapper.schema() + savingswhereClause;
this.columnValidator.validateSqlInjection(savingsAccountSummaryDataMapper.schema() , savingswhereClause);
return this.jdbcTemplate.query(savingsSql, savingsAccountSummaryDataMapper, inputs);
}
private static final class SavingsAccountSummaryDataMapper implements RowMapper<SavingsSummaryCustom> {
final String schemaSql;
public SavingsAccountSummaryDataMapper() {
final StringBuilder accountsSummary = new StringBuilder();
accountsSummary.append("sa.id as id, CONCAT('(',clnt.id,') ',clnt.display_name) as displayName,sa.account_no as accountNo, sa.external_id as externalId, sa.gsim_id as gsimId,gsim.account_number as parentAccountNo,sa.status_enum as statusEnum, ");
accountsSummary.append("sa.account_type_enum as accountType, ");
accountsSummary.append("sa.account_balance_derived as accountBalance, ");
accountsSummary.append("sa.submittedon_date as submittedOnDate,");
accountsSummary.append("sbu.username as submittedByUsername,");
accountsSummary.append("sbu.firstname as submittedByFirstname, sbu.lastname as submittedByLastname,");
accountsSummary.append("sa.rejectedon_date as rejectedOnDate,");
accountsSummary.append("rbu.username as rejectedByUsername,");
accountsSummary.append("rbu.firstname as rejectedByFirstname, rbu.lastname as rejectedByLastname,");
accountsSummary.append("sa.withdrawnon_date as withdrawnOnDate,");
accountsSummary.append("wbu.username as withdrawnByUsername,");
accountsSummary.append("wbu.firstname as withdrawnByFirstname, wbu.lastname as withdrawnByLastname,");
accountsSummary.append("sa.approvedon_date as approvedOnDate,");
accountsSummary.append("abu.username as approvedByUsername,");
accountsSummary.append("abu.firstname as approvedByFirstname, abu.lastname as approvedByLastname,");
accountsSummary.append("sa.activatedon_date as activatedOnDate,");
accountsSummary.append("avbu.username as activatedByUsername,");
accountsSummary.append("avbu.firstname as activatedByFirstname, avbu.lastname as activatedByLastname,");
accountsSummary.append("sa.sub_status_enum as subStatusEnum, ");
accountsSummary.append("(select IFNULL(max(sat.transaction_date),sa.activatedon_date) ");
accountsSummary.append("from m_savings_account_transaction as sat ");
accountsSummary.append("where sat.is_reversed = 0 ");
accountsSummary.append("and sat.transaction_type_enum in (1,2) ");
accountsSummary.append("and sat.savings_account_id = sa.id) as lastActiveTransactionDate, ");
accountsSummary.append("sa.closedon_date as closedOnDate,");
accountsSummary.append("cbu.username as closedByUsername,");
accountsSummary.append("cbu.firstname as closedByFirstname, cbu.lastname as closedByLastname,");
accountsSummary
.append("sa.currency_code as currencyCode, sa.currency_digits as currencyDigits, sa.currency_multiplesof as inMultiplesOf, ");
accountsSummary.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, ");
accountsSummary.append("curr.display_symbol as currencyDisplaySymbol, ");
accountsSummary.append("sa.product_id as productId, p.name as productName, p.short_name as shortProductName, ");
accountsSummary.append("sa.deposit_type_enum as depositType ");
accountsSummary.append("from m_savings_account sa ");
accountsSummary.append("join m_savings_product as p on p.id = sa.product_id ");
accountsSummary.append("join m_currency curr on curr.code = sa.currency_code ");
accountsSummary.append("left join m_appuser sbu on sbu.id = sa.submittedon_userid ");
accountsSummary.append("left join m_appuser rbu on rbu.id = sa.rejectedon_userid ");
accountsSummary.append("left join m_appuser wbu on wbu.id = sa.withdrawnon_userid ");
accountsSummary.append("left join m_appuser abu on abu.id = sa.approvedon_userid ");
accountsSummary.append("left join m_appuser avbu on rbu.id = sa.activatedon_userid ");
accountsSummary.append("left join m_appuser cbu on cbu.id = sa.closedon_userid ");
accountsSummary.append("left join gsim_accounts gsim on gsim.id=sa.gsim_id ");
accountsSummary.append("left join m_client clnt on clnt.id=sa.client_id ");
this.schemaSql = accountsSummary.toString();
}
public String schema() {
return this.schemaSql;
}
@Override
public SavingsSummaryCustom mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = JdbcSupport.getLong(rs, "id");
final String accountNo = rs.getString("accountNo");
final String displayName=rs.getString("displayName");
final String externalId = rs.getString("externalId");
final Long productId = JdbcSupport.getLong(rs, "productId");
final String productName = rs.getString("productName");
final String shortProductName = rs.getString("shortProductName");
final Integer statusId = JdbcSupport.getInteger(rs, "statusEnum");
final BigDecimal accountBalance = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "accountBalance");
final SavingsAccountStatusEnumData status = SavingsEnumerations.status(statusId);
final Integer accountType = JdbcSupport.getInteger(rs, "accountType");
final EnumOptionData accountTypeData = AccountEnumerations.loanType(accountType);
final Integer depositTypeId = JdbcSupport.getInteger(rs, "depositType");
final EnumOptionData depositTypeData = SavingsEnumerations.depositType(depositTypeId);
final String currencyCode = rs.getString("currencyCode");
final String currencyName = rs.getString("currencyName");
final String currencyNameCode = rs.getString("currencyNameCode");
final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
final Integer inMultiplesOf = JdbcSupport.getInteger(rs, "inMultiplesOf");
final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf,
currencyDisplaySymbol, currencyNameCode);
final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
final String submittedByUsername = rs.getString("submittedByUsername");
final String submittedByFirstname = rs.getString("submittedByFirstname");
final String submittedByLastname = rs.getString("submittedByLastname");
final LocalDate rejectedOnDate = JdbcSupport.getLocalDate(rs, "rejectedOnDate");
final String rejectedByUsername = rs.getString("rejectedByUsername");
final String rejectedByFirstname = rs.getString("rejectedByFirstname");
final String rejectedByLastname = rs.getString("rejectedByLastname");
final LocalDate withdrawnOnDate = JdbcSupport.getLocalDate(rs, "withdrawnOnDate");
final String withdrawnByUsername = rs.getString("withdrawnByUsername");
final String withdrawnByFirstname = rs.getString("withdrawnByFirstname");
final String withdrawnByLastname = rs.getString("withdrawnByLastname");
final LocalDate approvedOnDate = JdbcSupport.getLocalDate(rs, "approvedOnDate");
final String approvedByUsername = rs.getString("approvedByUsername");
final String approvedByFirstname = rs.getString("approvedByFirstname");
final String approvedByLastname = rs.getString("approvedByLastname");
final LocalDate activatedOnDate = JdbcSupport.getLocalDate(rs, "activatedOnDate");
final String activatedByUsername = rs.getString("activatedByUsername");
final String activatedByFirstname = rs.getString("activatedByFirstname");
final String activatedByLastname = rs.getString("activatedByLastname");
final LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate");
final String closedByUsername = rs.getString("closedByUsername");
final String closedByFirstname = rs.getString("closedByFirstname");
final String closedByLastname = rs.getString("closedByLastname");
final Integer subStatusEnum = JdbcSupport.getInteger(rs, "subStatusEnum");
final SavingsAccountSubStatusEnumData subStatus = SavingsEnumerations.subStatus(subStatusEnum);
final LocalDate lastActiveTransactionDate = JdbcSupport.getLocalDate(rs, "lastActiveTransactionDate");
final SavingsAccountApplicationTimelineData timeline = new SavingsAccountApplicationTimelineData(submittedOnDate,
submittedByUsername, submittedByFirstname, submittedByLastname, rejectedOnDate, rejectedByUsername,
rejectedByFirstname, rejectedByLastname, withdrawnOnDate, withdrawnByUsername, withdrawnByFirstname,
withdrawnByLastname, approvedOnDate, approvedByUsername, approvedByFirstname, approvedByLastname, activatedOnDate,
activatedByUsername, activatedByFirstname, activatedByLastname, closedOnDate, closedByUsername, closedByFirstname,
closedByLastname);
return new SavingsSummaryCustom(id,displayName, accountNo, externalId, productId, productName, shortProductName, status, currency, accountBalance,
accountTypeData, timeline, depositTypeData, subStatus, lastActiveTransactionDate);
}
}
}
@@ -0,0 +1,37 @@
/**
* 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.savings.service;
import java.math.BigDecimal;
import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.portfolio.savings.domain.GroupSavingsIndividualMonitoring;
public interface GroupSavingsIndividualMonitoringWritePlatformService
{
void setIsAcceptingChild(GroupSavingsIndividualMonitoring gsimAccount);
void resetIsAcceptingChild(GroupSavingsIndividualMonitoring gsimAccount);
void incrementChildAccountCount(GroupSavingsIndividualMonitoring gsimAccount);
GroupSavingsIndividualMonitoring addGSIMAccountInfo(String accountNumber, Group group, BigDecimal parentDeposit, Long childAccountsCount,
Boolean isAcceptingChild, Integer loanStatus, BigDecimal applicationId);
}
@@ -0,0 +1,88 @@
/**
* 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.savings.service;
import java.math.BigDecimal;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.apache.fineract.portfolio.savings.domain.GSIMRepositoy;
import org.apache.fineract.portfolio.savings.domain.GroupSavingsIndividualMonitoring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class GroupSavingsIndividualMonitoringWritePlatformServiceImpl implements GroupSavingsIndividualMonitoringWritePlatformService
{
private final PlatformSecurityContext context;
private final GSIMRepositoy gsimAccountRepository;
private final LoanRepository loanRepository;
@Autowired
public GroupSavingsIndividualMonitoringWritePlatformServiceImpl(final PlatformSecurityContext context,final GSIMRepositoy gsimAccountRepository,
final LoanRepository loanRepository)
{
this.context=context;
this.gsimAccountRepository=gsimAccountRepository;
this.loanRepository=loanRepository;
}
@Override
public GroupSavingsIndividualMonitoring addGSIMAccountInfo(String accountNumber,Group group,BigDecimal parentDeposit,Long childAccountsCount,
Boolean isAcceptingChild,Integer loanStatus,BigDecimal applicationId)
{
GroupSavingsIndividualMonitoring glimAccountInfo=GroupSavingsIndividualMonitoring.getInstance(accountNumber,group,parentDeposit,childAccountsCount,
isAcceptingChild,loanStatus,applicationId);
return this.gsimAccountRepository.save(glimAccountInfo );
}
@Override
public void setIsAcceptingChild(GroupSavingsIndividualMonitoring glimAccount)
{
glimAccount.setIsAcceptingChild(true);
gsimAccountRepository.save(glimAccount);
}
@Override
public void resetIsAcceptingChild(GroupSavingsIndividualMonitoring glimAccount)
{
glimAccount.setIsAcceptingChild(false);
gsimAccountRepository.save(glimAccount);
}
@Override
public void incrementChildAccountCount(GroupSavingsIndividualMonitoring glimAccount)
{
long count=glimAccount.getChildAccountsCount();
glimAccount.setChildAccountsCount(count+1);
gsimAccountRepository.save(glimAccount);
}
}
@@ -103,4 +103,10 @@ public interface SavingsAccountWritePlatformService {
CommandProcessingResult unblockDebits(Long savingsId);
CommandProcessingResult releaseAmount(Long savingsId, Long transactionId);
CommandProcessingResult gsimActivate(Long gsimId, JsonCommand command);
CommandProcessingResult gsimDeposit(Long gsimId, JsonCommand command);
CommandProcessingResult bulkGSIMClose(Long gsimId, JsonCommand command);
}
@@ -26,6 +26,8 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.dueAsOfD
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHoldTaxParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawBalanceParamName;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.ArrayList;
@@ -92,6 +94,8 @@ import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionDTO;
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionDataValidator;
import org.apache.fineract.portfolio.savings.domain.DepositAccountOnHoldTransaction;
import org.apache.fineract.portfolio.savings.domain.DepositAccountOnHoldTransactionRepository;
import org.apache.fineract.portfolio.savings.domain.GSIMRepositoy;
import org.apache.fineract.portfolio.savings.domain.GroupSavingsIndividualMonitoring;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountCharge;
@@ -115,6 +119,8 @@ import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -148,6 +154,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
private final AppUserRepositoryWrapper appuserRepository;
private final StandingInstructionRepository standingInstructionRepository;
private final BusinessEventNotifierService businessEventNotifierService;
private final GSIMRepositoy gsimRepository;
@Autowired
public SavingsAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -169,7 +176,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository,
final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService,
final AppUserRepositoryWrapper appuserRepository, final StandingInstructionRepository standingInstructionRepository,
final BusinessEventNotifierService businessEventNotifierService) {
final BusinessEventNotifierService businessEventNotifierService, final GSIMRepositoy gsimRepository) {
this.context = context;
this.savingAccountRepositoryWrapper = savingAccountRepositoryWrapper;
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
@@ -195,8 +202,33 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
this.appuserRepository = appuserRepository;
this.standingInstructionRepository = standingInstructionRepository;
this.businessEventNotifierService = businessEventNotifierService;
this.gsimRepository=gsimRepository;
}
private final static Logger logger = LoggerFactory.getLogger(SavingsAccountWritePlatformServiceJpaRepositoryImpl.class);
@Transactional
@Override
public CommandProcessingResult gsimActivate(final Long gsimId, final JsonCommand command) {
Long parentSavingId = gsimId;
GroupSavingsIndividualMonitoring parentSavings = gsimRepository.findById(parentSavingId).get();
List<SavingsAccount> childSavings = this.savingAccountRepositoryWrapper.findByGsimId(gsimId);
CommandProcessingResult result = null;
int count = 0;
for (SavingsAccount account : childSavings) {
result = activate(account.getId(), command);
if (result != null) {
count++;
if (count == parentSavings.getChildAccountsCount()) {
parentSavings.setSavingsStatus(SavingsAccountStatusType.ACTIVE.getValue());
gsimRepository.save(parentSavings);
}
}
}
return result;
}
@Transactional
@Override
public CommandProcessingResult activate(final Long savingsId, final JsonCommand command) {
@@ -265,6 +297,28 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
depositAccountOnHoldTransactions);
}
@Transactional
@Override
public CommandProcessingResult gsimDeposit(final Long gsimId, final JsonCommand command) {
Long parentSavingId = gsimId;
// GroupSavingsIndividualMonitoringparentSavings=gsimRepository.findById(parentSavingId).get();
List<SavingsAccount> childSavings = this.savingAccountRepositoryWrapper.findByGsimId(gsimId);
JsonArray savingsArray = command.arrayOfParameterNamed("savingsArray");
JsonArray childAccounts = command.arrayOfParameterNamed("childAccounts");
int count = 0;
CommandProcessingResult result = null;
for (JsonElement element : savingsArray) {
result = deposit(element.getAsJsonObject().get("childAccountId").getAsLong(),
JsonCommand.fromExistingCommand(command, element));
}
return result;
}
@Transactional
@Override
public CommandProcessingResult deposit(final Long savingsId, final JsonCommand command) {
@@ -272,6 +326,12 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
this.context.authenticatedUser();
this.savingsAccountTransactionDataValidator.validate(command);
boolean isGsim = false;
if (this.savingAccountRepositoryWrapper.findOneWithNotFoundDetection(savingsId).getGsim() != null) {
isGsim = true;
logger.info("is gsim");
}
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
checkClientOrGroupActive(account);
@@ -288,6 +348,21 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(account, fmt, transactionDate,
transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction);
if (isGsim && (deposit.getId() != null)) {
logger.debug("Deposit account has been created: {} ", deposit);
GroupSavingsIndividualMonitoring gsim = gsimRepository.findById(account.getGsim().getId()).get();
logger.info("parent deposit : {} ", gsim.getParentDeposit());
logger.info("child account : {} ", savingsId);
BigDecimal currentBalance = gsim.getParentDeposit();
BigDecimal newBalance = currentBalance.add(transactionAmount);
gsim.setParentDeposit(newBalance);
gsimRepository.save(gsim);
logger.info("balance after making deposit : {} ", gsimRepository.findById(account.getGsim().getId()).get().getParentDeposit());
}
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
final Note note = Note.savingsTransactionNote(account, deposit, noteText);
@@ -316,6 +391,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
this.savingsAccountTransactionDataValidator.validate(command);
boolean isGsim = false;
if (this.savingAccountRepositoryWrapper.findOneWithNotFoundDetection(savingsId).getGsim() != null) {
isGsim = true;
}
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
@@ -337,6 +417,14 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(account, fmt, transactionDate,
transactionAmount, paymentDetail, transactionBooleanValues);
if (isGsim && (withdrawal.getId() != null)) {
GroupSavingsIndividualMonitoring gsim = gsimRepository.findById(account.getGsim().getId()).get();
BigDecimal currentBalance = gsim.getParentDeposit().subtract(transactionAmount);
gsim.setParentDeposit(currentBalance);
gsimRepository.save(gsim);
}
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
final Note note = Note.savingsTransactionNote(account, withdrawal, noteText);
@@ -669,6 +757,29 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
}
}
@Override
public CommandProcessingResult bulkGSIMClose(final Long gsimId, final JsonCommand command) {
final Long parentSavingId = gsimId;
GroupSavingsIndividualMonitoring parentSavings = gsimRepository.findById(parentSavingId).get();
List<SavingsAccount> childSavings = this.savingAccountRepositoryWrapper.findByGsimId(gsimId);
CommandProcessingResult result = null;
int count = 0;
for (SavingsAccount account : childSavings) {
result = close(account.getId(), command);
if (result != null) {
count++;
if (count == parentSavings.getChildAccountsCount()) {
parentSavings.setSavingsStatus(SavingsAccountStatusType.CLOSED.getValue());
gsimRepository.save(parentSavings);
}
}
}
return result;
}
@Override
public CommandProcessingResult close(final Long savingsId, final JsonCommand command) {
final AppUser user = this.context.authenticatedUser();
@@ -1556,4 +1667,4 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
}
}
}
}
@@ -39,4 +39,14 @@ public interface SavingsApplicationProcessWritePlatformService {
CommandProcessingResult applicantWithdrawsFromApplication(Long savingsId, JsonCommand command);
CommandProcessingResult createActiveApplication(SavingsAccountDataDTO savingsAccountDataDTO);
CommandProcessingResult submitGSIMApplication(JsonCommand command);
CommandProcessingResult approveGSIMApplication(Long gsimId, JsonCommand command);
CommandProcessingResult rejectGSIMApplication(Long gsimId, JsonCommand command);
CommandProcessingResult undoGSIMApplicationApproval(Long gsimId, JsonCommand command);
CommandProcessingResult modifyGSIMApplication(Long gsimId, JsonCommand command);
}
@@ -20,6 +20,9 @@ package org.apache.fineract.portfolio.savings.service;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -60,6 +63,7 @@ import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.B
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.domain.GroupRepositoryWrapper;
import org.apache.fineract.portfolio.group.exception.CenterNotActiveException;
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
import org.apache.fineract.portfolio.group.exception.GroupNotFoundException;
@@ -68,12 +72,15 @@ import org.apache.fineract.portfolio.note.domain.NoteRepository;
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
import org.apache.fineract.portfolio.savings.data.SavingsAccountDataDTO;
import org.apache.fineract.portfolio.savings.data.SavingsAccountDataValidator;
import org.apache.fineract.portfolio.savings.domain.GSIMRepositoy;
import org.apache.fineract.portfolio.savings.domain.GroupSavingsIndividualMonitoring;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountCharge;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountChargeAssembler;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountDomainService;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType;
import org.apache.fineract.portfolio.savings.domain.SavingsProduct;
import org.apache.fineract.portfolio.savings.domain.SavingsProductRepository;
import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundException;
@@ -108,6 +115,9 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository;
private final BusinessEventNotifierService businessEventNotifierService;
private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
private final GSIMRepositoy gsimRepository;
private final GroupRepositoryWrapper groupRepositoryWrapper;
private final GroupSavingsIndividualMonitoringWritePlatformService gsimWritePlatformService;
@Autowired
public SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -122,7 +132,9 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
final SavingsAccountWritePlatformService savingsAccountWritePlatformService,
final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository,
final BusinessEventNotifierService businessEventNotifierService,
final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService) {
final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService,
final GSIMRepositoy gsimRepository, final GroupRepositoryWrapper groupRepositoryWrapper,
final GroupSavingsIndividualMonitoringWritePlatformService gsimWritePlatformService) {
this.context = context;
this.savingAccountRepository = savingAccountRepository;
this.savingAccountAssembler = savingAccountAssembler;
@@ -141,6 +153,9 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
this.savingsAccountWritePlatformService = savingsAccountWritePlatformService;
this.businessEventNotifierService = businessEventNotifierService ;
this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService;
this.gsimRepository = gsimRepository;
this.groupRepositoryWrapper = groupRepositoryWrapper;
this.gsimWritePlatformService = gsimWritePlatformService;
}
/*
@@ -170,6 +185,27 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
throw new PlatformDataIntegrityException(errorCodeBuilder.toString(), "Unknown data integrity issue with savings account.");
}
@Transactional
@Override
public CommandProcessingResult submitGSIMApplication(final JsonCommand command) {
CommandProcessingResult result = null;
JsonArray gsimApplications = command.arrayOfParameterNamed("clientArray");
final Object lock = new Object();
synchronized (lock){
for (JsonElement gsimApplication : gsimApplications) {
// result=submitApplication(JsonCommand.fromExistingCommand(command,
// gsimApplication));
result = submitApplication(JsonCommand.fromExistingCommand(command, gsimApplication,
gsimApplication.getAsJsonObject().get("clientId").getAsLong()));
}
}
return result;
}
@Transactional
@Override
public CommandProcessingResult submitApplication(final JsonCommand command) {
@@ -179,9 +215,88 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(command, submittedBy);
this.savingAccountRepository.save(account);
String accountNumber = "";
GroupSavingsIndividualMonitoring gsimAccount = null;
BigDecimal applicationId = BigDecimal.ZERO;
Boolean isLastChildApplication = false;
generateAccountNumber(account);
//gsim
if (account.isAccountNumberRequiresAutoGeneration()) {
final AccountNumberFormat accountNumberFormat = this.accountNumberFormatRepository
.findByAccountType(EntityAccountType.SAVINGS);
// if application is of GSIM type
if (account.getAccountTypes() == 5) {
final Long groupId = command.longValueOfParameterNamed("groupId");
// GSIM specific parameters
if (command.bigDecimalValueOfParameterNamedDefaultToNullIfZero("applicationId") != null) {
applicationId = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero("applicationId");
}
if (command.booleanObjectValueOfParameterNamed("lastApplication") != null) {
isLastChildApplication = command.booleanPrimitiveValueOfParameterNamed("lastApplication");
}
Group group = this.groupRepositoryWrapper.findOneWithNotFoundDetection(groupId);
if (command.booleanObjectValueOfParameterNamed("isParentAccount") != null)
{
// empty table check
if (gsimRepository.count() != 0) {
// Parent-Not an empty table
accountNumber = this.accountNumberGenerator.generate(account, accountNumberFormat);
account.updateAccountNo(accountNumber + "1");
gsimAccount = gsimWritePlatformService.addGSIMAccountInfo(accountNumber, group, BigDecimal.ZERO,
Long.valueOf(1), true,
SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.getValue(),applicationId);
account.setGsim(gsimAccount);
this.savingAccountRepository.save(account);
} else {
// Parent-empty table
accountNumber = this.accountNumberGenerator.generate(account, accountNumberFormat);
account.updateAccountNo(accountNumber + "1");
gsimWritePlatformService.addGSIMAccountInfo(accountNumber, group, BigDecimal.ZERO,
Long.valueOf(1), true,
SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.getValue(),applicationId);
account.setGsim(gsimRepository.findOneByAccountNumber(accountNumber));
this.savingAccountRepository.save(account);
}
} else {
if (gsimRepository.count() != 0) {
// Child-Not an empty table check
gsimAccount = gsimRepository.findOneByIsAcceptingChildAndApplicationId(true,applicationId);
accountNumber = gsimAccount.getAccountNumber()
+ (gsimAccount.getChildAccountsCount() + 1);
account.updateAccountNo(accountNumber);
this.gsimWritePlatformService.incrementChildAccountCount(gsimAccount);
account.setGsim(gsimAccount);
this.savingAccountRepository.save(account);
} else {
// Child-empty table
// if the gsim info is empty set the current account as parent
accountNumber = this.accountNumberGenerator.generate(account, accountNumberFormat);
account.updateAccountNo(accountNumber + "1");
gsimWritePlatformService.addGSIMAccountInfo(accountNumber, group, BigDecimal.ZERO,
Long.valueOf(1), true,
SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.getValue(),applicationId);
account.setGsim(gsimAccount);
this.savingAccountRepository.save(account);
}
//reset isAcceptingChild when processing last application of GSIM
if (isLastChildApplication) {
this.gsimWritePlatformService.resetIsAcceptingChild(
gsimRepository.findOneByIsAcceptingChildAndApplicationId(true, applicationId));
}
}
} else // for applications other than GSIM
{
generateAccountNumber(account);
}
}
// end of gsim
final Long savingsId = account.getId();
if(command.parameterExists(SavingsApiConstants.datatables)){
this.entityDatatableChecksWritePlatformService.saveDatatables(StatusEnum.CREATE.getCode().longValue(),
@@ -202,6 +317,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
.withClientId(account.clientId()) //
.withGroupId(account.groupId()) //
.withSavingsId(savingsId) //
.withGsimId(gsimAccount==null ? 0 : gsimAccount.getId())
.build();
} catch (final DataAccessException dve) {
handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
@@ -222,6 +338,22 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
}
}
@Transactional
@Override
public CommandProcessingResult modifyGSIMApplication(final Long gsimId, final JsonCommand command) {
final Long parentSavingId = gsimId;
List<SavingsAccount> childSavings = this.savingAccountRepository.findByGsimId(parentSavingId);
CommandProcessingResult result = null;
for (SavingsAccount account : childSavings) {
result = modifyApplication(account.getId(), command);
}
return result;
}
@Transactional
@Override
public CommandProcessingResult modifyApplication(final Long savingsId, final JsonCommand command) {
@@ -347,6 +479,32 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
.build();
}
@Transactional
@Override
public CommandProcessingResult approveGSIMApplication(final Long gsimId, final JsonCommand command) {
// GroupLoanIndividualMonitoringAccount
// glimAccount=glimRepository.findOne(loanId);
Long parentSavingId = gsimId;
GroupSavingsIndividualMonitoring parentSavings = gsimRepository.findById(parentSavingId).get();
List<SavingsAccount> childSavings = this.savingAccountRepository.findByGsimId(gsimId);
CommandProcessingResult result = null;
int count = 0;
for (SavingsAccount account : childSavings) {
result = approveApplication(account.getId(), command);
if (result != null) {
count++;
if (count == parentSavings.getChildAccountsCount()) {
parentSavings.setSavingsStatus(SavingsAccountStatusType.APPROVED.getValue());
gsimRepository.save(parentSavings);
}
}
}
return result;
}
@Transactional
@Override
public CommandProcessingResult approveApplication(final Long savingsId, final JsonCommand command) {
@@ -389,6 +547,31 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
.build();
}
@Transactional
@Override
public CommandProcessingResult undoGSIMApplicationApproval(final Long gsimId, final JsonCommand command) {
final Long parentSavingId = gsimId;
GroupSavingsIndividualMonitoring parentSavings = gsimRepository.findById(parentSavingId).get();
List<SavingsAccount> childSavings = this.savingAccountRepository.findByGsimId(gsimId);
CommandProcessingResult result = null;
int count = 0;
for (SavingsAccount account : childSavings) {
result = undoApplicationApproval(account.getId(), command);
if (result != null) {
count++;
if (count == parentSavings.getChildAccountsCount()) {
parentSavings.setSavingsStatus(SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.getValue());
gsimRepository.save(parentSavings);
}
}
}
return result;
}
@Transactional
@Override
public CommandProcessingResult undoApplicationApproval(final Long savingsId, final JsonCommand command) {
@@ -423,6 +606,30 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
.build();
}
@Transactional
@Override
public CommandProcessingResult rejectGSIMApplication(final Long gsimId, final JsonCommand command) {
final Long parentSavingId = gsimId;
GroupSavingsIndividualMonitoring parentSavings = gsimRepository.findById(parentSavingId).get();
List<SavingsAccount> childSavings = this.savingAccountRepository.findByGsimId(gsimId);
CommandProcessingResult result = null;
int count = 0;
for (SavingsAccount account : childSavings) {
result = rejectApplication(account.getId(), command);
if (result != null) {
count++;
if (count == parentSavings.getChildAccountsCount()) {
parentSavings.setSavingsStatus(SavingsAccountStatusType.REJECTED.getValue());
gsimRepository.save(parentSavings);
}
}
}
return result;
}
@Transactional
@Override
public CommandProcessingResult rejectApplication(final Long savingsId, final JsonCommand command) {
@@ -41,87 +41,82 @@ import org.springframework.stereotype.Component;
@Component
public class SelfSavingsDataValidator {
private final FromJsonHelper fromApiJsonHelper;
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public SelfSavingsDataValidator(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
@Autowired
public SelfSavingsDataValidator(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
private static final Set<String> allowedAssociationParameters = new HashSet<>(
Arrays.asList(SavingsApiConstants.transactions,
SavingsApiConstants.charges));
private static final Set<String> allowedAssociationParameters = new HashSet<>(
Arrays.asList(SavingsApiConstants.transactions, SavingsApiConstants.charges));
public void validateRetrieveSavings(final UriInfo uriInfo) {
List<String> unsupportedParams = new ArrayList<>();
public void validateRetrieveSavings(final UriInfo uriInfo) {
List<String> unsupportedParams = new ArrayList<>();
validateTemplate(uriInfo, unsupportedParams);
validateTemplate(uriInfo, unsupportedParams);
Set<String> associationParameters = ApiParameterHelper
.extractAssociationsForResponseIfProvided(uriInfo
.getQueryParameters());
if (!associationParameters.isEmpty()) {
associationParameters.removeAll(allowedAssociationParameters);
if (!associationParameters.isEmpty()) {
unsupportedParams.addAll(associationParameters);
}
}
Set<String> associationParameters = ApiParameterHelper
.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
if (!associationParameters.isEmpty()) {
associationParameters.removeAll(allowedAssociationParameters);
if (!associationParameters.isEmpty()) {
unsupportedParams.addAll(associationParameters);
}
}
if (uriInfo.getQueryParameters().getFirst("exclude") != null) {
unsupportedParams.add("exclude");
}
if (uriInfo.getQueryParameters().getFirst("exclude") != null) {
unsupportedParams.add("exclude");
}
throwExceptionIfReqd(unsupportedParams);
}
throwExceptionIfReqd(unsupportedParams);
}
public void validateRetrieveSavingsTransaction(final UriInfo uriInfo) {
List<String> unsupportedParams = new ArrayList<>();
public void validateRetrieveSavingsTransaction(final UriInfo uriInfo) {
List<String> unsupportedParams = new ArrayList<>();
validateTemplate(uriInfo, unsupportedParams);
validateTemplate(uriInfo, unsupportedParams);
throwExceptionIfReqd(unsupportedParams);
}
throwExceptionIfReqd(unsupportedParams);
}
private void throwExceptionIfReqd(final List<String> unsupportedParams) {
if (unsupportedParams.size() > 0) {
throw new UnsupportedParameterException(unsupportedParams);
}
}
private void throwExceptionIfReqd(final List<String> unsupportedParams) {
if (unsupportedParams.size() > 0) {
throw new UnsupportedParameterException(unsupportedParams);
}
}
private void validateTemplate(final UriInfo uriInfo,
List<String> unsupportedParams) {
final boolean templateRequest = ApiParameterHelper.template(uriInfo
.getQueryParameters());
if (templateRequest) {
unsupportedParams.add("template");
}
}
private void validateTemplate(final UriInfo uriInfo, List<String> unsupportedParams) {
final boolean templateRequest = ApiParameterHelper.template(uriInfo.getQueryParameters());
if (templateRequest) {
unsupportedParams.add("template");
}
}
public HashMap<String, Object> validateSavingsApplication(final String json) {
if (StringUtils.isBlank(json)) {
throw new InvalidJsonException();
}
public HashMap<String, Object> validateSavingsApplication(final String json) {
if (StringUtils.isBlank(json)) {
throw new InvalidJsonException();
}
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SelfSavingsAccountConstants.savingsAccountResource);
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SelfSavingsAccountConstants.savingsAccountResource);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final Long clientId = this.fromApiJsonHelper.extractLongNamed(SelfSavingsAccountConstants.clientIdParameterName,
element);
baseDataValidator.reset().parameter(SelfSavingsAccountConstants.clientIdParameterName).value(clientId).notNull()
.longGreaterThanZero();
final Long clientId = this.fromApiJsonHelper.extractLongNamed(SelfSavingsAccountConstants.clientIdParameterName,
element);
baseDataValidator.reset().parameter(SelfSavingsAccountConstants.clientIdParameterName).value(clientId).notNull()
.longGreaterThanZero();
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
HashMap<String, Object> parameterMap = new HashMap<>();
parameterMap.put(SelfSavingsAccountConstants.clientIdParameterName, clientId);
HashMap<String, Object> parameterMap = new HashMap<>();
parameterMap.put(SelfSavingsAccountConstants.clientIdParameterName, clientId);
return parameterMap;
return parameterMap;
}
}
}
}
@@ -0,0 +1,63 @@
--
-- 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.
--
-- permissions added
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'CREATE_GSIMACCOUNT', 'GSIMACCOUNT', 'CREATE', 0);
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'APPROVE_GSIMACCOUNT', 'GSIMACCOUNT', 'APPROVE', 0);
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'ACTIVATE_GSIMACCOUNT', 'GSIMACCOUNT', 'ACTIVATE', 0);
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'APPROVALUNDO_GSIMACCOUNT', 'GSIMACCOUNT', 'APPROVALUNDO', 0);
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'UPDATE_GSIMACCOUNT', 'GSIMACCOUNT', 'UPDATE', 0);
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'REJECT_GSIMACCOUNT', 'GSIMACCOUNT', 'REJECT', 0);
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'DEPOSIT_GSIMACCOUNT', 'GSIMACCOUNT', 'DEPOSIT', 0);
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'CLOSE_GSIMACCOUNT', 'GSIMACCOUNT', 'CLOSE', 0);
-- new gsim table
CREATE TABLE `gsim_accounts` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`group_id` BIGINT(20) NOT NULL DEFAULT '0',
`account_number` VARCHAR(50) NOT NULL,
`parent_deposit` DECIMAL(19,6) NOT NULL DEFAULT '0.000000',
`child_accounts_count` INT(11) NOT NULL,
`accepting_child` TINYINT(4) NOT NULL DEFAULT '0',
`savings_status_id` SMALLINT(5) NOT NULL DEFAULT '0',
`application_id` DECIMAL(10,0) NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE INDEX `gsim_account_no_UNIQUE` (`account_number`),
INDEX `FK_gsim_group_id` (`group_id`),
CONSTRAINT `FK_gsim_group_id` FOREIGN KEY (`group_id`) REFERENCES `m_group` (`id`)
);
-- changes to savings
ALTER TABLE `m_savings_account` ADD COLUMN `gsim_id` bigint(20) DEFAULT NULL AFTER `group_id`;
ALTER TABLE `m_savings_account` ADD CONSTRAINT `FK_gsim_id` FOREIGN KEY (`gsim_id`) REFERENCES `gsim_accounts` (`id`);
-- changes to savings_Transaction
ALTER TABLE `m_savings_account_transaction` ADD COLUMN `is_loan_disbursement` bigint(20);
@@ -0,0 +1,58 @@
--
-- 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.
--
-- permissions added
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'APPROVE_GLIMLOAN', 'GLIMLOAN', 'APPROVE', 0);
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'DISBURSE_GLIMLOAN', 'GLIMLOAN', 'DISBURSE', 0);
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'REPAYMENT_GLIMLOAN', 'GLIMLOAN', 'REPAYMENT', 0);
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'UNDODISBURSAL_GLIMLOAN', 'GLIMLOAN', 'UNDODISBURSAL', 0);
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'UNDOAPPROVAL_GLIMLOAN', 'GLIMLOAN', 'UNDOAPPROVAL', 0);
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'REJECT_GLIMLOAN', 'GLIMLOAN', 'REJECT', 0);
-- new table glim_accounts added
CREATE TABLE `glim_accounts` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`group_id` BIGINT(20) NOT NULL DEFAULT '0',
`account_number` VARCHAR(50) NOT NULL,
`principal_amount` DECIMAL(19,6) NOT NULL DEFAULT '0.000000',
`child_accounts_count` INT(11) NOT NULL,
`accepting_child` TINYINT(4) NOT NULL DEFAULT '0',
`loan_status_id` SMALLINT(5) NOT NULL DEFAULT '0',
`application_id` DECIMAL(10,0) NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE INDEX `glim_account_no_UNIQUE` (`account_number`),
INDEX `FK_group_id` (`group_id`),
CONSTRAINT `FK_group_id` FOREIGN KEY (`group_id`) REFERENCES `m_group` (`id`)
);
-- change m_loan table
alter table `m_loan` add COLUMN `glim_id` bigint(20) DEFAULT NULL AFTER `group_id`;
alter table `m_loan` add CONSTRAINT `FK_glim_id` FOREIGN KEY (`glim_id`) REFERENCES `glim_accounts` (`id`);