FINERACT-1932: Fineract modularization - fineract-savings
This commit is contained in:
committed by
Adam Saghy
parent
1f00bb6d33
commit
02cf6749af
+241
@@ -0,0 +1,241 @@
|
||||
/**
|
||||
* 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.accounting.producttoaccountmapping.service;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.SavingProductAccountingParams;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
import org.apache.fineract.accounting.glaccount.domain.GLAccountRepository;
|
||||
import org.apache.fineract.accounting.glaccount.domain.GLAccountRepositoryWrapper;
|
||||
import org.apache.fineract.accounting.glaccount.domain.GLAccountType;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.domain.PortfolioProductType;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.domain.ProductToGLAccountMappingRepository;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.paymenttype.domain.PaymentTypeRepositoryWrapper;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMappingHelper {
|
||||
|
||||
public SavingsProductToGLAccountMappingHelper(final GLAccountRepository glAccountRepository,
|
||||
final ProductToGLAccountMappingRepository glAccountMappingRepository, final FromJsonHelper fromApiJsonHelper,
|
||||
final ChargeRepositoryWrapper chargeRepositoryWrapper, final GLAccountRepositoryWrapper accountRepositoryWrapper,
|
||||
final PaymentTypeRepositoryWrapper paymentTypeRepositoryWrapper) {
|
||||
super(glAccountRepository, glAccountMappingRepository, fromApiJsonHelper, chargeRepositoryWrapper, accountRepositoryWrapper,
|
||||
paymentTypeRepositoryWrapper);
|
||||
}
|
||||
|
||||
/***
|
||||
* Set of abstractions for saving Saving Products to GL Account Mappings
|
||||
***/
|
||||
|
||||
public void saveSavingsToAssetAccountMapping(final JsonElement element, final String paramName, final Long productId,
|
||||
final int placeHolderTypeId) {
|
||||
saveProductToAccountMapping(element, paramName, productId, placeHolderTypeId, GLAccountType.ASSET, PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public void saveSavingsToIncomeAccountMapping(final JsonElement element, final String paramName, final Long productId,
|
||||
final int placeHolderTypeId) {
|
||||
saveProductToAccountMapping(element, paramName, productId, placeHolderTypeId, GLAccountType.INCOME, PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public void saveSavingsToExpenseAccountMapping(final JsonElement element, final String paramName, final Long productId,
|
||||
final int placeHolderTypeId) {
|
||||
saveProductToAccountMapping(element, paramName, productId, placeHolderTypeId, GLAccountType.EXPENSE, PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public void saveSavingsToLiabilityAccountMapping(final JsonElement element, final String paramName, final Long productId,
|
||||
final int placeHolderTypeId) {
|
||||
saveProductToAccountMapping(element, paramName, productId, placeHolderTypeId, GLAccountType.LIABILITY, PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
/***
|
||||
* Set of abstractions for merging Savings Products to GL Account Mappings
|
||||
***/
|
||||
|
||||
public void mergeSavingsToAssetAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes) {
|
||||
mergeProductToAccountMappingChanges(element, paramName, productId, accountTypeId, accountTypeName, changes, GLAccountType.ASSET,
|
||||
PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public void mergeSavingsToIncomeAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes) {
|
||||
mergeProductToAccountMappingChanges(element, paramName, productId, accountTypeId, accountTypeName, changes, GLAccountType.INCOME,
|
||||
PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public void mergeSavingsToExpenseAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes) {
|
||||
mergeProductToAccountMappingChanges(element, paramName, productId, accountTypeId, accountTypeName, changes, GLAccountType.EXPENSE,
|
||||
PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public void mergeSavingsToLiabilityAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes) {
|
||||
mergeProductToAccountMappingChanges(element, paramName, productId, accountTypeId, accountTypeName, changes, GLAccountType.LIABILITY,
|
||||
PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public void createOrmergeSavingsToLiabilityAccountMappingChanges(final JsonElement element, final String paramName,
|
||||
final Long productId, final int accountTypeId, final Map<String, Object> changes) {
|
||||
createOrmergeProductToAccountMappingChanges(element, paramName, productId, accountTypeId, changes, GLAccountType.LIABILITY,
|
||||
PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
/*** Abstractions for payments channel related to savings products ***/
|
||||
|
||||
public void savePaymentChannelToFundSourceMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
final Map<String, Object> changes) {
|
||||
savePaymentChannelToFundSourceMappings(command, element, productId, changes, PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public void updatePaymentChannelToFundSourceMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
final Map<String, Object> changes) {
|
||||
updatePaymentChannelToFundSourceMappings(command, element, productId, changes, PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public void saveChargesToIncomeAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
final Map<String, Object> changes) {
|
||||
// save both fee and penalty charges
|
||||
saveChargesToGLAccountMappings(command, element, productId, changes, PortfolioProductType.SAVING, true);
|
||||
saveChargesToGLAccountMappings(command, element, productId, changes, PortfolioProductType.SAVING, false);
|
||||
}
|
||||
|
||||
public void updateChargesToIncomeAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
final Map<String, Object> changes) {
|
||||
// update both fee and penalty charges
|
||||
updateChargeToIncomeAccountMappings(command, element, productId, changes, PortfolioProductType.SAVING, true);
|
||||
updateChargeToIncomeAccountMappings(command, element, productId, changes, PortfolioProductType.SAVING, false);
|
||||
}
|
||||
|
||||
public Map<String, Object> populateChangesForNewSavingsProductToGLAccountMappingCreation(final JsonElement element,
|
||||
final AccountingRuleType accountingRuleType) {
|
||||
final Map<String, Object> changes = new HashMap<>();
|
||||
|
||||
final Long savingsReferenceId = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(),
|
||||
element);
|
||||
final Long incomeFromFeesId = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_FEES.getValue(),
|
||||
element);
|
||||
final Long incomeFromPenaltiesId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), element);
|
||||
final Long interestOnSavingsId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), element);
|
||||
final Long savingsControlId = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.SAVINGS_CONTROL.getValue(),
|
||||
element);
|
||||
final Long transfersInSuspenseAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), element);
|
||||
final Long overdraftControlId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), element);
|
||||
final Long incomeFromInterest = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(), element);
|
||||
final Long writeOffId = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(),
|
||||
element);
|
||||
switch (accountingRuleType) {
|
||||
case NONE:
|
||||
break;
|
||||
case CASH_BASED:
|
||||
changes.put(SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), savingsControlId);
|
||||
changes.put(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), savingsReferenceId);
|
||||
changes.put(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), interestOnSavingsId);
|
||||
changes.put(SavingProductAccountingParams.INCOME_FROM_FEES.getValue(), incomeFromFeesId);
|
||||
changes.put(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), incomeFromPenaltiesId);
|
||||
changes.put(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), transfersInSuspenseAccountId);
|
||||
changes.put(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), overdraftControlId);
|
||||
changes.put(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(), incomeFromInterest);
|
||||
changes.put(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), writeOffId);
|
||||
break;
|
||||
case ACCRUAL_PERIODIC:
|
||||
break;
|
||||
case ACCRUAL_UPFRONT:
|
||||
break;
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Examines and updates each account mapping for given loan product with changes passed in from the Json element
|
||||
*
|
||||
* @param savingsProductId
|
||||
* @param changes
|
||||
* @param element
|
||||
* @param accountingRuleType
|
||||
*/
|
||||
public void handleChangesToSavingsProductToGLAccountMappings(final Long savingsProductId, final Map<String, Object> changes,
|
||||
final JsonElement element, final AccountingRuleType accountingRuleType) {
|
||||
switch (accountingRuleType) {
|
||||
case NONE:
|
||||
break;
|
||||
case CASH_BASED:
|
||||
// asset
|
||||
mergeSavingsToAssetAccountMappingChanges(element, SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(),
|
||||
savingsProductId, CashAccountsForSavings.SAVINGS_REFERENCE.getValue(),
|
||||
CashAccountsForSavings.SAVINGS_REFERENCE.toString(), changes);
|
||||
|
||||
mergeSavingsToAssetAccountMappingChanges(element, SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
savingsProductId, CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.toString(), changes);
|
||||
|
||||
// income
|
||||
mergeSavingsToIncomeAccountMappingChanges(element, SavingProductAccountingParams.INCOME_FROM_FEES.getValue(),
|
||||
savingsProductId, CashAccountsForSavings.INCOME_FROM_FEES.getValue(),
|
||||
CashAccountsForSavings.INCOME_FROM_FEES.toString(), changes);
|
||||
|
||||
mergeSavingsToIncomeAccountMappingChanges(element, SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(),
|
||||
savingsProductId, CashAccountsForSavings.INCOME_FROM_PENALTIES.getValue(),
|
||||
CashAccountsForSavings.INCOME_FROM_PENALTIES.toString(), changes);
|
||||
|
||||
mergeSavingsToIncomeAccountMappingChanges(element, SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(),
|
||||
savingsProductId, CashAccountsForSavings.INCOME_FROM_INTEREST.getValue(),
|
||||
CashAccountsForSavings.INCOME_FROM_INTEREST.toString(), changes);
|
||||
|
||||
// expenses
|
||||
mergeSavingsToExpenseAccountMappingChanges(element, SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(),
|
||||
savingsProductId, CashAccountsForSavings.INTEREST_ON_SAVINGS.getValue(),
|
||||
CashAccountsForSavings.INTEREST_ON_SAVINGS.toString(), changes);
|
||||
mergeSavingsToExpenseAccountMappingChanges(element, SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(),
|
||||
savingsProductId, CashAccountsForSavings.LOSSES_WRITTEN_OFF.getValue(),
|
||||
CashAccountsForSavings.LOSSES_WRITTEN_OFF.toString(), changes);
|
||||
|
||||
// liability
|
||||
mergeSavingsToLiabilityAccountMappingChanges(element, SavingProductAccountingParams.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, CashAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
CashAccountsForSavings.SAVINGS_CONTROL.toString(), changes);
|
||||
mergeSavingsToLiabilityAccountMappingChanges(element, SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(),
|
||||
savingsProductId, CashAccountsForSavings.TRANSFERS_SUSPENSE.getValue(),
|
||||
CashAccountsForSavings.TRANSFERS_SUSPENSE.toString(), changes);
|
||||
createOrmergeSavingsToLiabilityAccountMappingChanges(element, SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue(),
|
||||
savingsProductId, CashAccountsForSavings.ESCHEAT_LIABILITY.getValue(), changes);
|
||||
break;
|
||||
case ACCRUAL_PERIODIC:
|
||||
break;
|
||||
case ACCRUAL_UPFRONT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteSavingsProductToGLAccountMapping(final Long savingsProductId) {
|
||||
deleteProductToGLAccountMapping(savingsProductId, PortfolioProductType.SAVING);
|
||||
}
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* 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.interoperation.data;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.interoperation.domain.InteropIdentifier;
|
||||
import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
|
||||
import org.apache.fineract.portfolio.savings.DepositAccountType;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountSubStatusEnum;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProduct;
|
||||
|
||||
public class InteropAccountData extends CommandProcessingResult {
|
||||
|
||||
@NotNull
|
||||
private final String accountId;
|
||||
@NotNull
|
||||
private final String savingProductId;
|
||||
@NotNull
|
||||
private final String productName;
|
||||
@NotNull
|
||||
private final String shortProductName;
|
||||
@NotNull
|
||||
private final String currency;
|
||||
@NotNull
|
||||
private final BigDecimal accountBalance;
|
||||
@NotNull
|
||||
private final BigDecimal availableBalance;
|
||||
@NotNull
|
||||
private final SavingsAccountStatusType status;
|
||||
private final SavingsAccountSubStatusEnum subStatus;
|
||||
|
||||
private final AccountType accountType; // differentiate Individual, JLG or
|
||||
// Group account
|
||||
private final DepositAccountType depositType; // differentiate deposit
|
||||
// accounts Savings, FD and RD
|
||||
// accounts
|
||||
@NotNull
|
||||
private final LocalDate activatedOn;
|
||||
private final LocalDate statusUpdateOn;
|
||||
private final LocalDate withdrawnOn;
|
||||
private final LocalDate balanceOn;
|
||||
@NotNull
|
||||
private List<InteropIdentifierData> identifiers;
|
||||
|
||||
InteropAccountData(Long resourceId, Long officeId, Long commandId, Map<String, Object> changesOnly, String accountId, String productId,
|
||||
String productName, String shortProductName, String currency, BigDecimal accountBalance, BigDecimal availableBalance,
|
||||
SavingsAccountStatusType status, SavingsAccountSubStatusEnum subStatus, AccountType accountType, DepositAccountType depositType,
|
||||
LocalDate activatedOn, LocalDate statusUpdateOn, LocalDate withdrawnOn, LocalDate balanceOn,
|
||||
List<InteropIdentifierData> identifiers, long clientId) {
|
||||
super(resourceId, officeId, commandId, changesOnly, clientId);
|
||||
this.accountId = accountId;
|
||||
this.savingProductId = productId;
|
||||
this.productName = productName;
|
||||
this.shortProductName = shortProductName;
|
||||
this.currency = currency;
|
||||
this.accountBalance = accountBalance;
|
||||
this.availableBalance = availableBalance;
|
||||
this.status = status;
|
||||
this.subStatus = subStatus;
|
||||
this.accountType = accountType;
|
||||
this.depositType = depositType;
|
||||
this.activatedOn = activatedOn;
|
||||
this.statusUpdateOn = statusUpdateOn;
|
||||
this.withdrawnOn = withdrawnOn;
|
||||
this.balanceOn = balanceOn;
|
||||
this.identifiers = identifiers;
|
||||
}
|
||||
|
||||
InteropAccountData(String accountId, String productId, String productName, String shortProductName, String currency,
|
||||
BigDecimal accountBalance, BigDecimal availableBalance, SavingsAccountStatusType status, SavingsAccountSubStatusEnum subStatus,
|
||||
AccountType accountType, DepositAccountType depositType, LocalDate activatedOn, LocalDate statusUpdateOn, LocalDate withdrawnOn,
|
||||
LocalDate balanceOn, List<InteropIdentifierData> identifiers, long clientId) {
|
||||
this(null, null, null, null, accountId, productId, productName, shortProductName, currency, accountBalance, availableBalance,
|
||||
status, subStatus, accountType, depositType, activatedOn, statusUpdateOn, withdrawnOn, balanceOn, identifiers, clientId);
|
||||
}
|
||||
|
||||
public static InteropAccountData build(SavingsAccount account) {
|
||||
if (account == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<InteropIdentifierData> ids = new ArrayList<>();
|
||||
for (InteropIdentifier identifier : account.getIdentifiers()) {
|
||||
ids.add(InteropIdentifierData.build(identifier));
|
||||
}
|
||||
|
||||
SavingsProduct product = account.savingsProduct();
|
||||
SavingsAccountSubStatusEnum subStatus = SavingsAccountSubStatusEnum.fromInt(account.getSubStatus());
|
||||
|
||||
return new InteropAccountData(account.getExternalId().getValue(), product.getId().toString(), product.getName(),
|
||||
product.getShortName(), account.getCurrency().getCode(), account.getAccountBalance(), account.getWithdrawableBalance(),
|
||||
account.getStatus(), subStatus, account.getAccountType(), account.depositAccountType(), account.getActivationDate(),
|
||||
calcStatusUpdateOn(account), account.getWithdrawnOnDate(), account.retrieveLastTransactionDate(), ids,
|
||||
account.getClient().getId());
|
||||
}
|
||||
|
||||
private static LocalDate calcStatusUpdateOn(@NotNull SavingsAccount account) {
|
||||
if (account.getClosedOnDate() != null) {
|
||||
return account.getClosedOnDate();
|
||||
}
|
||||
if (account.getWithdrawnOnDate() != null) {
|
||||
return account.getWithdrawnOnDate();
|
||||
}
|
||||
if (account.getActivationDate() != null) {
|
||||
return account.getActivationDate();
|
||||
}
|
||||
if (account.getRejectedOnDate() != null) {
|
||||
return account.getRejectedOnDate();
|
||||
}
|
||||
if (account.getApprovedOnDate() != null) {
|
||||
return account.getApprovedOnDate();
|
||||
}
|
||||
if (account.getSubmittedOnDate() != null) {
|
||||
return account.getSubmittedOnDate();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 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.interoperation.data;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import org.apache.fineract.interoperation.domain.InteropIdentifier;
|
||||
import org.apache.fineract.interoperation.domain.InteropIdentifierType;
|
||||
|
||||
public class InteropIdentifierData {
|
||||
|
||||
@NotNull
|
||||
private final InteropIdentifierType idType;
|
||||
|
||||
@NotNull
|
||||
private final String idValue;
|
||||
|
||||
private final String subIdOrType;
|
||||
|
||||
public InteropIdentifierData(@NotNull InteropIdentifierType idType, @NotNull String idValue, String subIdOrType) {
|
||||
this.idType = idType;
|
||||
this.idValue = idValue;
|
||||
this.subIdOrType = subIdOrType;
|
||||
}
|
||||
|
||||
protected InteropIdentifierData(@NotNull InteropIdentifierType idType, @NotNull String idValue) {
|
||||
this(idType, idValue, null);
|
||||
}
|
||||
|
||||
public InteropIdentifierType getIdType() {
|
||||
return idType;
|
||||
}
|
||||
|
||||
public String getIdValue() {
|
||||
return idValue;
|
||||
}
|
||||
|
||||
public String getSubIdOrType() {
|
||||
return subIdOrType;
|
||||
}
|
||||
|
||||
public static InteropIdentifierData build(InteropIdentifier identifier) {
|
||||
return new InteropIdentifierData(identifier.getType(), identifier.getValue(), identifier.getSubType());
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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.interoperation.domain;
|
||||
|
||||
public enum InteropActionState {
|
||||
ACCEPTED, REJECTED
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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.interoperation.domain;
|
||||
|
||||
public enum InteropAmountType {
|
||||
SEND, RECEIVE
|
||||
}
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* 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.interoperation.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Objects;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
|
||||
|
||||
@Entity
|
||||
@Table(name = "interop_identifier", uniqueConstraints = {
|
||||
@UniqueConstraint(name = "uk_hathor_identifier_account", columnNames = { "account_id", "type" }),
|
||||
@UniqueConstraint(name = "uk_hathor_identifier_value", columnNames = { "type", "a_value", "sub_value_or_type" }) })
|
||||
public class InteropIdentifier extends AbstractPersistableCustom {
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "account_id", nullable = false)
|
||||
private SavingsAccount account;
|
||||
|
||||
@Column(name = "type", nullable = false, length = 32)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private InteropIdentifierType type;
|
||||
|
||||
@Column(name = "a_value", nullable = false, length = 128)
|
||||
private String value;
|
||||
|
||||
@Column(name = "sub_value_or_type", length = 128)
|
||||
private String subType;
|
||||
|
||||
@Column(name = "created_by", nullable = false, length = 32)
|
||||
private String createdBy;
|
||||
|
||||
@Column(name = "created_on", nullable = false)
|
||||
private LocalDateTime createdOn;
|
||||
|
||||
@Column(name = "modified_by", length = 32)
|
||||
private String modifiedBy;
|
||||
|
||||
@Column(name = "modified_on")
|
||||
private LocalDateTime modifiedOn;
|
||||
|
||||
protected InteropIdentifier() {}
|
||||
|
||||
public InteropIdentifier(@NotNull SavingsAccount account, @NotNull InteropIdentifierType type, @NotNull String value, String subType,
|
||||
@NotNull String createdBy) {
|
||||
this.account = account;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
this.subType = subType;
|
||||
this.createdBy = createdBy;
|
||||
this.createdOn = DateUtils.getAuditLocalDateTime();
|
||||
}
|
||||
|
||||
public InteropIdentifier(@NotNull SavingsAccount account, @NotNull InteropIdentifierType type, @NotNull String createdBy) {
|
||||
this(account, type, null, null, createdBy);
|
||||
}
|
||||
|
||||
public SavingsAccount getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
public InteropIdentifierType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getSubType() {
|
||||
return subType;
|
||||
}
|
||||
|
||||
public void setSubType(String subType) {
|
||||
this.subType = subType;
|
||||
}
|
||||
|
||||
public String getCreatedBy() {
|
||||
return createdBy;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedOn() {
|
||||
return createdOn;
|
||||
}
|
||||
|
||||
public String geModifiedBy() {
|
||||
return modifiedBy;
|
||||
}
|
||||
|
||||
public void setModifiedBy(String modifiedBy) {
|
||||
this.modifiedBy = modifiedBy;
|
||||
}
|
||||
|
||||
public LocalDateTime getModifiedOn() {
|
||||
return modifiedOn;
|
||||
}
|
||||
|
||||
public void setModifiedOn(LocalDateTime modifiedOn) {
|
||||
this.modifiedOn = modifiedOn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || !(o instanceof InteropIdentifier)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
InteropIdentifier that = (InteropIdentifier) o;
|
||||
|
||||
if (!account.equals(that.account)) {
|
||||
return false;
|
||||
}
|
||||
if (type != that.type) {
|
||||
return false;
|
||||
}
|
||||
if (!value.equals(that.value)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(subType, that.subType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = type.hashCode();
|
||||
result = 31 * result + value.hashCode();
|
||||
result = 31 * result + (subType != null ? subType.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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.interoperation.domain;
|
||||
|
||||
public enum InteropIdentifierType {
|
||||
|
||||
MSISDN, EMAIL, PERSONAL_ID, BUSINESS, DEVICE, ACCOUNT_ID, IBAN, ALIAS
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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.interoperation.domain;
|
||||
|
||||
public enum InteropInitiatorType {
|
||||
CONSUMER, AGENT, BUSINESS, DEVICE
|
||||
}
|
||||
+34
@@ -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.interoperation.domain;
|
||||
|
||||
import org.apache.fineract.portfolio.savings.SavingsAccountTransactionType;
|
||||
|
||||
public enum InteropTransactionRole {
|
||||
|
||||
PAYER, PAYEE,;
|
||||
|
||||
public boolean isWithdraw() {
|
||||
return this == PAYER;
|
||||
}
|
||||
|
||||
public SavingsAccountTransactionType getTransactionType() {
|
||||
return this == PAYER ? SavingsAccountTransactionType.WITHDRAWAL : SavingsAccountTransactionType.DEPOSIT;
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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.interoperation.domain;
|
||||
|
||||
public enum InteropTransactionScenario {
|
||||
|
||||
DEPOSIT, WITHDRAWAL, TRANSFER, PAYMENT, REFUND
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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.interoperation.domain;
|
||||
|
||||
public enum InteropTransferActionType {
|
||||
|
||||
PREPARE, CREATE, RELEASE;
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 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 java.time.LocalDate;
|
||||
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;
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* 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.charge.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class SavingsAccountChargeCannotBeWaivedException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
/*** enum of reasons of why Savings Account Charge cannot be waived **/
|
||||
public enum SavingsAccountChargeCannotBeWaivedReason {
|
||||
|
||||
ALREADY_PAID, ALREADY_WAIVED, SAVINGS_ACCOUNT_NOT_ACTIVE, SAVINGS_ACCOUNT_CLOSED;
|
||||
|
||||
public String errorMessage() {
|
||||
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
|
||||
return "This savings account charge has been completely paid";
|
||||
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
|
||||
return "This savings account charge has already been waived";
|
||||
} else if (name().toString().equalsIgnoreCase("SAVINGS_ACCOUNT_NOT_ACTIVE")) {
|
||||
return "This savings account charge cannot be waived as the Savings account associated with it is not active";
|
||||
} else if (name().toString().equalsIgnoreCase("SAVINGS_ACCOUNT_CLOSED")) {
|
||||
return "This savings account charge cannot be waived as the Savings account associated with it is closed";
|
||||
}
|
||||
return name().toString();
|
||||
}
|
||||
|
||||
public String errorCode() {
|
||||
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
|
||||
return "error.msg.savings.account.charge.already.paid";
|
||||
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
|
||||
return "error.msg.savings.account.charge.already.waived";
|
||||
} else if (name().toString().equalsIgnoreCase("SAVINGS_ACCOUNT_NOT_ACTIVE")) {
|
||||
return "error.msg.savings.account.charge.associated.savings.account.not.active";
|
||||
} else if (name().toString().equalsIgnoreCase("SAVINGS_ACCOUNT_CLOSED")) {
|
||||
return "error.msg.savings.account.charge.associated.savings.account.closed";
|
||||
}
|
||||
return name().toString();
|
||||
}
|
||||
}
|
||||
|
||||
public SavingsAccountChargeCannotBeWaivedException(final SavingsAccountChargeCannotBeWaivedReason reason,
|
||||
final Long savingsAccountChargeId) {
|
||||
super(reason.errorCode(), reason.errorMessage(), savingsAccountChargeId);
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.charge.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
|
||||
/**
|
||||
* {@link AbstractPlatformDomainRuleException} thrown when savings account charge does not exist.
|
||||
*/
|
||||
public class SavingsAccountChargeNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||
|
||||
public SavingsAccountChargeNotFoundException(final Long id) {
|
||||
super("error.msg.savings.account.charge.id.invalid", "Savings Account charge with identifier " + id + " does not exist", id);
|
||||
}
|
||||
|
||||
public SavingsAccountChargeNotFoundException(final Long id, final Long savingsAccountId) {
|
||||
super("error.msg.savings.account.charge.id.invalid.for.given.savings.account",
|
||||
"Savings Account charge with identifier " + id + " does not exist for Savings Account " + savingsAccountId, id,
|
||||
savingsAccountId);
|
||||
}
|
||||
|
||||
public SavingsAccountChargeNotFoundException(Long id, EmptyResultDataAccessException e) {
|
||||
super("error.msg.savings.account.charge.id.invalid", "Savings Account charge with identifier " + id + " does not exist", id, e);
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.charge.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
/**
|
||||
* {@link AbstractPlatformDomainRuleException} thrown when currency mismatch occurs
|
||||
*/
|
||||
public class SavingsAccountChargeWithoutMandatoryFieldException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public SavingsAccountChargeWithoutMandatoryFieldException(final String entity, final String postFix, final String defaultUserMessage,
|
||||
final Object... defaultUserMessageArgs) {
|
||||
super("error.msg." + entity + "." + postFix + ".cannot.be.blank", defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 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.interestratechart;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public interface InterestIncentiveApiConstants {
|
||||
|
||||
String idParamName = "id";
|
||||
String entityTypeParamName = "entityType";
|
||||
String attributeNameParamName = "attributeName";
|
||||
String conditionTypeParamName = "conditionType";
|
||||
String attributeValueParamName = "attributeValue";
|
||||
String incentiveTypeparamName = "incentiveType";
|
||||
String amountParamName = "amount";
|
||||
String deleteParamName = "delete";
|
||||
|
||||
String INCENTIVE_RESOURCE_NAME = "interest.rate.incentives";
|
||||
|
||||
Set<String> INTERESTRATE_INCENTIVE_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName, entityTypeParamName,
|
||||
attributeNameParamName, conditionTypeParamName, attributeValueParamName, incentiveTypeparamName, amountParamName));
|
||||
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* 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.interestratechart;
|
||||
|
||||
public final class InterestRateChartApiConstants {
|
||||
|
||||
private InterestRateChartApiConstants() {
|
||||
|
||||
}
|
||||
|
||||
public static final String INTERESTRATE_CHART_RESOURCE_NAME = "interestchart";
|
||||
|
||||
// actions
|
||||
public static final String summitalAction = ".summital";
|
||||
|
||||
// command
|
||||
public static final String COMMAND_UNDO_TRANSACTION = "undo";
|
||||
|
||||
// general
|
||||
public static final String localeParamName = "locale";
|
||||
public static final String dateFormatParamName = "dateFormat";
|
||||
|
||||
// interest rate chart parameters
|
||||
public static final String idParamName = "id";
|
||||
public static final String nameParamName = "name";
|
||||
public static final String descriptionParamName = "description";
|
||||
public static final String fromDateParamName = "fromDate";
|
||||
public static final String endDateParamName = "endDate";
|
||||
public static final String productIdParamName = "productId";
|
||||
public static final String productNameParamName = "productName";
|
||||
public static final String isPrimaryGroupingByAmountParamName = "isPrimaryGroupingByAmount";
|
||||
|
||||
// interest rate chart Slabs parameters
|
||||
// public static final String periodTypeParamName = "periodType";
|
||||
// public static final String fromPeriodParamName = "fromPeriod";
|
||||
// public static final String toPeriodParamName = "toPeriod";
|
||||
// public static final String amountRangeFromParamName = "amountRangeFrom";
|
||||
// public static final String amountRangeToParamName = "amountRangeTo";
|
||||
// public static final String annualInterestRateParamName =
|
||||
// "annualInterestRate";
|
||||
// public static final String interestRateForFemaleParamName =
|
||||
// "interestRateForFemale";
|
||||
// public static final String interestRateForChildrenParamName =
|
||||
// "interestRateForChildren";
|
||||
// public static final String interestRateForSeniorCitizenParamName =
|
||||
// "interestRateForSeniorCitizen";
|
||||
|
||||
// associations
|
||||
public static final String chartSlabs = "chartSlabs";
|
||||
|
||||
// to delete chart Slabs from chart
|
||||
public static final String deleteParamName = "delete";
|
||||
}
|
||||
+48
@@ -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.interestratechart;
|
||||
|
||||
public final class InterestRateChartSlabApiConstants {
|
||||
|
||||
private InterestRateChartSlabApiConstants() {
|
||||
|
||||
}
|
||||
|
||||
public static final String INTERESTRATE_CHART_SLAB_RESOURCE_NAME = "chartslab";
|
||||
|
||||
// actions
|
||||
|
||||
// command
|
||||
|
||||
// general
|
||||
public static final String localeParamName = "locale";
|
||||
public static final String dateFormatParamName = "dateFormat";
|
||||
|
||||
// interest rate chart Slabs parameters
|
||||
public static final String idParamName = "id";
|
||||
public static final String descriptionParamName = "description";
|
||||
public static final String periodTypeParamName = "periodType";
|
||||
public static final String fromPeriodParamName = "fromPeriod";
|
||||
public static final String toPeriodParamName = "toPeriod";
|
||||
public static final String amountRangeFromParamName = "amountRangeFrom";
|
||||
public static final String amountRangeToParamName = "amountRangeTo";
|
||||
public static final String annualInterestRateParamName = "annualInterestRate";
|
||||
public static final String currencyCodeParamName = "currencyCode";
|
||||
public static final String incentivesParamName = "incentives";
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* 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.interestratechart.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
|
||||
public final class InterestIncentiveData {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Long id;
|
||||
private final EnumOptionData entityType;
|
||||
private final EnumOptionData attributeName;
|
||||
private final EnumOptionData conditionType;
|
||||
private final String attributeValue;
|
||||
private final String attributeValueDesc;
|
||||
private final EnumOptionData incentiveType;
|
||||
private final BigDecimal amount;
|
||||
|
||||
public static InterestIncentiveData instance(final Long id, final EnumOptionData entityType, final EnumOptionData attributeName,
|
||||
final EnumOptionData conditionType, final String attributeValue, final String attributeValueDesc,
|
||||
final EnumOptionData incentiveType, final BigDecimal amount) {
|
||||
|
||||
return new InterestIncentiveData(id, entityType, attributeName, conditionType, attributeValue, attributeValueDesc, incentiveType,
|
||||
amount);
|
||||
}
|
||||
|
||||
private InterestIncentiveData(final Long id, final EnumOptionData entityType, final EnumOptionData attributeName,
|
||||
final EnumOptionData conditionType, final String attributeValue, final String attributeValueDesc,
|
||||
final EnumOptionData incentiveType, final BigDecimal amount) {
|
||||
|
||||
this.id = id;
|
||||
this.entityType = entityType;
|
||||
this.attributeName = attributeName;
|
||||
this.conditionType = conditionType;
|
||||
this.attributeValue = attributeValue;
|
||||
this.attributeValueDesc = attributeValueDesc;
|
||||
this.incentiveType = incentiveType;
|
||||
this.amount = amount;
|
||||
|
||||
}
|
||||
|
||||
public EnumOptionData entityType() {
|
||||
return this.entityType;
|
||||
}
|
||||
|
||||
public EnumOptionData attributeName() {
|
||||
return this.attributeName;
|
||||
}
|
||||
|
||||
public EnumOptionData conditionType() {
|
||||
return this.conditionType;
|
||||
}
|
||||
|
||||
public String attributeValue() {
|
||||
return this.attributeValue;
|
||||
}
|
||||
|
||||
public EnumOptionData incentiveType() {
|
||||
return this.incentiveType;
|
||||
}
|
||||
|
||||
public BigDecimal amount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public String attributeValueDesc() {
|
||||
return this.attributeValueDesc;
|
||||
}
|
||||
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.interestratechart.data;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
|
||||
/**
|
||||
* Immutable data object representing a InterestRateChart.
|
||||
*/
|
||||
public final class InterestRateChartData {
|
||||
|
||||
private final Long id;
|
||||
private final String name;
|
||||
private final String description;
|
||||
private final LocalDate fromDate;
|
||||
private final LocalDate endDate;
|
||||
private final Long productId;
|
||||
private final String productName;
|
||||
private final boolean isPrimaryGroupingByAmount;
|
||||
|
||||
// associations
|
||||
private Collection<InterestRateChartSlabData> chartSlabs;
|
||||
|
||||
// template
|
||||
private final Collection<EnumOptionData> periodTypes;
|
||||
private final Collection<EnumOptionData> entityTypeOptions;
|
||||
private final Collection<EnumOptionData> attributeNameOptions;
|
||||
private final Collection<EnumOptionData> conditionTypeOptions;
|
||||
private final Collection<EnumOptionData> incentiveTypeOptions;
|
||||
private final Collection<CodeValueData> genderOptions;
|
||||
private final Collection<CodeValueData> clientTypeOptions;
|
||||
private final Collection<CodeValueData> clientClassificationOptions;
|
||||
|
||||
public static InterestRateChartData instance(Long id, String name, String description, LocalDate fromDate, LocalDate endDate,
|
||||
boolean isPrimaryGroupingByAmount, Long savingsProductId, String savingsProductName) {
|
||||
Collection<EnumOptionData> periodTypes = null;
|
||||
Collection<InterestRateChartSlabData> chartSlabs = null;
|
||||
final Collection<EnumOptionData> entityTypeOptions = null;
|
||||
final Collection<EnumOptionData> attributeNameOptions = null;
|
||||
final Collection<EnumOptionData> conditionTypeOptions = null;
|
||||
final Collection<EnumOptionData> incentiveTypeOptions = null;
|
||||
final Collection<CodeValueData> genderOptions = null;
|
||||
final Collection<CodeValueData> clientTypeOptions = null;
|
||||
final Collection<CodeValueData> clientClassificationOptions = null;
|
||||
return new InterestRateChartData(id, name, description, fromDate, endDate, isPrimaryGroupingByAmount, savingsProductId,
|
||||
savingsProductName, chartSlabs, periodTypes, entityTypeOptions, attributeNameOptions, conditionTypeOptions,
|
||||
incentiveTypeOptions, genderOptions, clientTypeOptions, clientClassificationOptions);
|
||||
}
|
||||
|
||||
public static InterestRateChartData withSlabs(InterestRateChartData interestRateChartData,
|
||||
Collection<InterestRateChartSlabData> chartSlabs) {
|
||||
return new InterestRateChartData(interestRateChartData.id, interestRateChartData.name, interestRateChartData.description,
|
||||
interestRateChartData.fromDate, interestRateChartData.endDate, interestRateChartData.isPrimaryGroupingByAmount,
|
||||
interestRateChartData.productId, interestRateChartData.productName, chartSlabs, interestRateChartData.periodTypes,
|
||||
interestRateChartData.entityTypeOptions, interestRateChartData.attributeNameOptions,
|
||||
interestRateChartData.conditionTypeOptions, interestRateChartData.incentiveTypeOptions, interestRateChartData.genderOptions,
|
||||
interestRateChartData.clientTypeOptions, interestRateChartData.clientClassificationOptions);
|
||||
}
|
||||
|
||||
public static InterestRateChartData withTemplate(InterestRateChartData interestRateChartData, Collection<EnumOptionData> periodTypes,
|
||||
final Collection<EnumOptionData> entityTypeOptions, final Collection<EnumOptionData> attributeNameOptions,
|
||||
final Collection<EnumOptionData> conditionTypeOptions, final Collection<EnumOptionData> incentiveTypeOptions,
|
||||
final Collection<CodeValueData> genderOptions, final Collection<CodeValueData> clientTypeOptions,
|
||||
final Collection<CodeValueData> clientClassificationOptions) {
|
||||
return new InterestRateChartData(interestRateChartData.id, interestRateChartData.name, interestRateChartData.description,
|
||||
interestRateChartData.fromDate, interestRateChartData.endDate, interestRateChartData.isPrimaryGroupingByAmount,
|
||||
interestRateChartData.productId, interestRateChartData.productName, interestRateChartData.chartSlabs, periodTypes,
|
||||
entityTypeOptions, attributeNameOptions, conditionTypeOptions, incentiveTypeOptions, genderOptions, clientTypeOptions,
|
||||
clientClassificationOptions);
|
||||
}
|
||||
|
||||
public static InterestRateChartData template(Collection<EnumOptionData> periodTypes, final Collection<EnumOptionData> entityTypeOptions,
|
||||
final Collection<EnumOptionData> attributeNameOptions, final Collection<EnumOptionData> conditionTypeOptions,
|
||||
final Collection<EnumOptionData> incentiveTypeOptions, final Collection<CodeValueData> genderOptions,
|
||||
final Collection<CodeValueData> clientTypeOptions, final Collection<CodeValueData> clientClassificationOptions) {
|
||||
final Long id = null;
|
||||
final String name = null;
|
||||
final String description = null;
|
||||
final LocalDate fromDate = null;
|
||||
final LocalDate endDate = null;
|
||||
final boolean isPrimaryGroupingByAmount = false;
|
||||
final Long savingsProductId = null;
|
||||
final String savingsProductName = null;
|
||||
final Collection<InterestRateChartSlabData> chartSlabs = null;
|
||||
|
||||
return new InterestRateChartData(id, name, description, fromDate, endDate, isPrimaryGroupingByAmount, savingsProductId,
|
||||
savingsProductName, chartSlabs, periodTypes, entityTypeOptions, attributeNameOptions, conditionTypeOptions,
|
||||
incentiveTypeOptions, genderOptions, clientTypeOptions, clientClassificationOptions);
|
||||
}
|
||||
|
||||
private InterestRateChartData(Long id, String name, String description, LocalDate fromDate, LocalDate endDate,
|
||||
boolean isPrimaryGroupingByAmount, Long savingsProductId, String savingsProductName,
|
||||
Collection<InterestRateChartSlabData> chartSlabs, Collection<EnumOptionData> periodTypes,
|
||||
final Collection<EnumOptionData> entityTypeOptions, final Collection<EnumOptionData> attributeNameOptions,
|
||||
final Collection<EnumOptionData> conditionTypeOptions, final Collection<EnumOptionData> incentiveTypeOptions,
|
||||
final Collection<CodeValueData> genderOptions, final Collection<CodeValueData> clientTypeOptions,
|
||||
final Collection<CodeValueData> clientClassificationOptions) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.fromDate = fromDate;
|
||||
this.endDate = endDate;
|
||||
this.isPrimaryGroupingByAmount = isPrimaryGroupingByAmount;
|
||||
this.chartSlabs = chartSlabs;
|
||||
this.productId = savingsProductId;
|
||||
this.productName = savingsProductName;
|
||||
this.periodTypes = periodTypes;
|
||||
this.attributeNameOptions = attributeNameOptions;
|
||||
this.entityTypeOptions = entityTypeOptions;
|
||||
this.conditionTypeOptions = conditionTypeOptions;
|
||||
this.incentiveTypeOptions = incentiveTypeOptions;
|
||||
this.genderOptions = genderOptions;
|
||||
this.clientTypeOptions = clientTypeOptions;
|
||||
this.clientClassificationOptions = clientClassificationOptions;
|
||||
}
|
||||
|
||||
public void addChartSlab(final InterestRateChartSlabData chartSlab) {
|
||||
if (this.chartSlabs == null) {
|
||||
this.chartSlabs = new ArrayList<>();
|
||||
}
|
||||
|
||||
this.chartSlabs.add(chartSlab);
|
||||
}
|
||||
|
||||
public boolean isFromDateAfter(final LocalDate compareDate) {
|
||||
return compareDate != null && DateUtils.isAfter(this.fromDate, compareDate);
|
||||
}
|
||||
|
||||
public LocalDate endDate() {
|
||||
return this.endDate;
|
||||
}
|
||||
|
||||
public LocalDate fromDate() {
|
||||
return this.fromDate;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String description() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public Collection<InterestRateChartSlabData> chartSlabs() {
|
||||
return this.chartSlabs;
|
||||
}
|
||||
|
||||
public Collection<EnumOptionData> periodTypes() {
|
||||
return this.periodTypes;
|
||||
}
|
||||
|
||||
public Collection<EnumOptionData> entityTypeOptions() {
|
||||
return this.entityTypeOptions;
|
||||
}
|
||||
|
||||
public Collection<EnumOptionData> attributeNameOptions() {
|
||||
return this.attributeNameOptions;
|
||||
}
|
||||
|
||||
public Collection<EnumOptionData> conditionTypeOptions() {
|
||||
return this.conditionTypeOptions;
|
||||
}
|
||||
|
||||
public Collection<EnumOptionData> incentiveTypeOptions() {
|
||||
return this.incentiveTypeOptions;
|
||||
}
|
||||
|
||||
public Collection<CodeValueData> genderOptions() {
|
||||
return this.genderOptions;
|
||||
}
|
||||
|
||||
public Collection<CodeValueData> clientTypeOptions() {
|
||||
return this.clientTypeOptions;
|
||||
}
|
||||
|
||||
public Collection<CodeValueData> clientClassificationOptions() {
|
||||
return this.clientClassificationOptions;
|
||||
}
|
||||
|
||||
public boolean isPrimaryGroupingByAmount() {
|
||||
return this.isPrimaryGroupingByAmount;
|
||||
}
|
||||
|
||||
}
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
/**
|
||||
* 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.interestratechart.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
|
||||
/**
|
||||
* Immutable data object representing a InterestRateChartSlab.
|
||||
*/
|
||||
public final class InterestRateChartSlabData {
|
||||
|
||||
private final Long id;
|
||||
private final String description;
|
||||
private final EnumOptionData periodType;
|
||||
private final Integer fromPeriod;
|
||||
private final Integer toPeriod;
|
||||
private final BigDecimal amountRangeFrom;
|
||||
private final BigDecimal amountRangeTo;
|
||||
private final BigDecimal annualInterestRate;
|
||||
private final CurrencyData currency;
|
||||
|
||||
// associations
|
||||
private Set<InterestIncentiveData> incentives;
|
||||
|
||||
// template
|
||||
private final Collection<EnumOptionData> periodTypes;
|
||||
private final Collection<EnumOptionData> entityTypeOptions;
|
||||
private final Collection<EnumOptionData> attributeNameOptions;
|
||||
private final Collection<EnumOptionData> conditionTypeOptions;
|
||||
private final Collection<EnumOptionData> incentiveTypeOptions;
|
||||
private final Collection<CodeValueData> genderOptions;
|
||||
private final Collection<CodeValueData> clientTypeOptions;
|
||||
private final Collection<CodeValueData> clientClassificationOptions;
|
||||
|
||||
public static InterestRateChartSlabData instance(final Long id, final String description, final EnumOptionData periodType,
|
||||
final Integer fromPeriod, final Integer toPeriod, final BigDecimal amountRangeFrom, final BigDecimal amountRangeTo,
|
||||
final BigDecimal annualInterestRate, final CurrencyData currency) {
|
||||
final Collection<EnumOptionData> periodTypes = null;
|
||||
final Set<InterestIncentiveData> incentivesData = null;
|
||||
final Collection<EnumOptionData> entityTypeOptions = null;
|
||||
final Collection<EnumOptionData> attributeNameOptions = null;
|
||||
final Collection<EnumOptionData> conditionTypeOptions = null;
|
||||
final Collection<EnumOptionData> incentiveTypeOptions = null;
|
||||
final Collection<CodeValueData> genderOptions = null;
|
||||
final Collection<CodeValueData> clientTypeOptions = null;
|
||||
final Collection<CodeValueData> clientClassificationOptions = null;
|
||||
return new InterestRateChartSlabData(id, description, periodType, fromPeriod, toPeriod, amountRangeFrom, amountRangeTo,
|
||||
annualInterestRate, currency, incentivesData, periodTypes, entityTypeOptions, attributeNameOptions, conditionTypeOptions,
|
||||
incentiveTypeOptions, genderOptions, clientTypeOptions, clientClassificationOptions);
|
||||
}
|
||||
|
||||
public static InterestRateChartSlabData withTemplate(final InterestRateChartSlabData chartSlab,
|
||||
final Collection<EnumOptionData> periodTypes, final Collection<EnumOptionData> entityTypeOptions,
|
||||
final Collection<EnumOptionData> attributeNameOptions, final Collection<EnumOptionData> conditionTypeOptions,
|
||||
final Collection<EnumOptionData> incentiveTypeOptions, final Collection<CodeValueData> genderOptions,
|
||||
final Collection<CodeValueData> clientTypeOptions, final Collection<CodeValueData> clientClassificationOptions) {
|
||||
return new InterestRateChartSlabData(chartSlab.id, chartSlab.description, chartSlab.periodType, chartSlab.fromPeriod,
|
||||
chartSlab.toPeriod, chartSlab.amountRangeFrom, chartSlab.amountRangeTo, chartSlab.annualInterestRate, chartSlab.currency,
|
||||
chartSlab.incentives, periodTypes, entityTypeOptions, attributeNameOptions, conditionTypeOptions, incentiveTypeOptions,
|
||||
genderOptions, clientTypeOptions, clientClassificationOptions);
|
||||
}
|
||||
|
||||
public static InterestRateChartSlabData template(final Collection<EnumOptionData> periodTypes,
|
||||
final Collection<EnumOptionData> entityTypeOptions, final Collection<EnumOptionData> attributeNameOptions,
|
||||
final Collection<EnumOptionData> conditionTypeOptions, final Collection<EnumOptionData> incentiveTypeOptions,
|
||||
final Collection<CodeValueData> genderOptions, final Collection<CodeValueData> clientTypeOptions,
|
||||
final Collection<CodeValueData> clientClassificationOptions) {
|
||||
final Long id = null;
|
||||
final String description = null;
|
||||
final EnumOptionData periodType = null;
|
||||
final Integer fromPeriod = null;
|
||||
final Integer toPeriod = null;
|
||||
final BigDecimal amountRangeFrom = null;
|
||||
final BigDecimal amountRangeTo = null;
|
||||
final BigDecimal annualInterestRate = null;
|
||||
final CurrencyData currency = null;
|
||||
final Set<InterestIncentiveData> incentivesData = null;
|
||||
return new InterestRateChartSlabData(id, description, periodType, fromPeriod, toPeriod, amountRangeFrom, amountRangeTo,
|
||||
annualInterestRate, currency, incentivesData, periodTypes, entityTypeOptions, attributeNameOptions, conditionTypeOptions,
|
||||
incentiveTypeOptions, genderOptions, clientTypeOptions, clientClassificationOptions);
|
||||
}
|
||||
|
||||
private InterestRateChartSlabData(final Long id, final String description, final EnumOptionData periodType, final Integer fromPeriod,
|
||||
final Integer toPeriod, final BigDecimal amountRangeFrom, final BigDecimal amountRangeTo, final BigDecimal annualInterestRate,
|
||||
final CurrencyData currency, final Set<InterestIncentiveData> incentivesData, final Collection<EnumOptionData> periodTypes,
|
||||
final Collection<EnumOptionData> entityTypeOptions, final Collection<EnumOptionData> attributeNameOptions,
|
||||
final Collection<EnumOptionData> conditionTypeOptions, final Collection<EnumOptionData> incentiveTypeOptions,
|
||||
final Collection<CodeValueData> genderOptions, final Collection<CodeValueData> clientTypeOptions,
|
||||
final Collection<CodeValueData> clientClassificationOptions) {
|
||||
this.id = id;
|
||||
this.description = description;
|
||||
this.periodType = periodType;
|
||||
this.fromPeriod = fromPeriod;
|
||||
this.toPeriod = toPeriod;
|
||||
this.amountRangeFrom = amountRangeFrom;
|
||||
this.amountRangeTo = amountRangeTo;
|
||||
this.annualInterestRate = annualInterestRate;
|
||||
this.currency = currency;
|
||||
this.periodTypes = periodTypes;
|
||||
this.incentives = incentivesData;
|
||||
this.attributeNameOptions = attributeNameOptions;
|
||||
this.entityTypeOptions = entityTypeOptions;
|
||||
this.conditionTypeOptions = conditionTypeOptions;
|
||||
this.incentiveTypeOptions = incentiveTypeOptions;
|
||||
this.genderOptions = genderOptions;
|
||||
this.clientTypeOptions = clientTypeOptions;
|
||||
this.clientClassificationOptions = clientClassificationOptions;
|
||||
}
|
||||
|
||||
public String description() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public EnumOptionData periodType() {
|
||||
return this.periodType;
|
||||
}
|
||||
|
||||
public Integer fromPeriod() {
|
||||
return this.fromPeriod;
|
||||
}
|
||||
|
||||
public Integer toPeriod() {
|
||||
return this.toPeriod;
|
||||
}
|
||||
|
||||
public BigDecimal amountRangeFrom() {
|
||||
return this.amountRangeFrom;
|
||||
}
|
||||
|
||||
public BigDecimal amountRangeTo() {
|
||||
return this.amountRangeTo;
|
||||
}
|
||||
|
||||
public BigDecimal annualInterestRate() {
|
||||
return this.annualInterestRate;
|
||||
}
|
||||
|
||||
public CurrencyData currency() {
|
||||
return this.currency;
|
||||
}
|
||||
|
||||
public Collection<EnumOptionData> periodTypes() {
|
||||
return this.periodTypes;
|
||||
}
|
||||
|
||||
public void addIncentives(final InterestIncentiveData incentiveData) {
|
||||
if (this.incentives == null) {
|
||||
this.incentives = new HashSet<>();
|
||||
}
|
||||
|
||||
this.incentives.add(incentiveData);
|
||||
}
|
||||
|
||||
public Set<InterestIncentiveData> incentives() {
|
||||
return this.incentives;
|
||||
}
|
||||
|
||||
public Collection<EnumOptionData> entityTypeOptions() {
|
||||
return this.entityTypeOptions;
|
||||
}
|
||||
|
||||
public Collection<EnumOptionData> attributeNameOptions() {
|
||||
return this.attributeNameOptions;
|
||||
}
|
||||
|
||||
public Collection<EnumOptionData> conditionTypeOptions() {
|
||||
return this.conditionTypeOptions;
|
||||
}
|
||||
|
||||
public Collection<EnumOptionData> incentiveTypeOptions() {
|
||||
return this.incentiveTypeOptions;
|
||||
}
|
||||
|
||||
public Collection<CodeValueData> genderOptions() {
|
||||
return this.genderOptions;
|
||||
}
|
||||
|
||||
public Collection<CodeValueData> clientTypeOptions() {
|
||||
return this.clientTypeOptions;
|
||||
}
|
||||
|
||||
public Collection<CodeValueData> clientClassificationOptions() {
|
||||
return this.clientClassificationOptions;
|
||||
}
|
||||
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* 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.interestratechart.domain;
|
||||
|
||||
import jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_interest_incentives")
|
||||
public class InterestIncentives extends AbstractPersistableCustom {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "interest_rate_slab_id", nullable = false)
|
||||
private InterestRateChartSlab interestRateChartSlab;
|
||||
|
||||
@Embedded
|
||||
private InterestIncentivesFields interestIncentivesFields;
|
||||
|
||||
protected InterestIncentives() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* public InterestIncentives(final InterestRateChartSlab interestRateChartSlab, final InterestIncentivesFields
|
||||
* interestIncentivesFields) { this.interestRateChartSlab = interestRateChartSlab; this.interestIncentivesFields =
|
||||
* interestIncentivesFields; }
|
||||
*/
|
||||
|
||||
public InterestRateChartSlab interestRateChartSlab() {
|
||||
return this.interestRateChartSlab;
|
||||
}
|
||||
|
||||
public void updateInterestRateChartSlab(InterestRateChartSlab interestRateChartSlab) {
|
||||
this.interestRateChartSlab = interestRateChartSlab;
|
||||
}
|
||||
|
||||
public InterestIncentives(final InterestRateChartSlab interestRateChartSlab, final InterestIncentivesFields interestIncentivesFields) {
|
||||
this.interestRateChartSlab = interestRateChartSlab;
|
||||
this.interestIncentivesFields = interestIncentivesFields;
|
||||
if (this.interestRateChartSlab != null) {
|
||||
interestRateChartSlab.addInterestIncentive(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void update(final JsonCommand command, final Map<String, Object> actualChanges, final DataValidatorBuilder baseDataValidator,
|
||||
final Locale locale) {
|
||||
this.interestIncentivesFields.update(command, actualChanges, baseDataValidator, locale);
|
||||
}
|
||||
|
||||
public InterestIncentivesFields interestIncentivesFields() {
|
||||
return this.interestIncentivesFields;
|
||||
}
|
||||
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* 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.interestratechart.domain;
|
||||
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.amountParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.attributeNameParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.attributeValueParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.conditionTypeParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.entityTypeParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.incentiveTypeparamName;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.portfolio.common.domain.ConditionType;
|
||||
import org.apache.fineract.portfolio.interestratechart.incentive.InterestIncentiveAttributeName;
|
||||
import org.apache.fineract.portfolio.interestratechart.incentive.InterestIncentiveEntityType;
|
||||
import org.apache.fineract.portfolio.interestratechart.incentive.InterestIncentiveType;
|
||||
|
||||
@Embeddable
|
||||
public class InterestIncentivesFields {
|
||||
|
||||
@Column(name = "entiry_type", nullable = false)
|
||||
private Integer entityType;
|
||||
|
||||
@Column(name = "attribute_name", nullable = false)
|
||||
private Integer attributeName;
|
||||
|
||||
@Column(name = "condition_type", nullable = false)
|
||||
private Integer conditionType;
|
||||
|
||||
@Column(name = "attribute_value", nullable = false)
|
||||
private String attributeValue;
|
||||
|
||||
@Column(name = "incentive_type", nullable = false)
|
||||
private Integer incentiveType;
|
||||
|
||||
@Column(name = "amount", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal amount;
|
||||
|
||||
protected InterestIncentivesFields() {
|
||||
|
||||
}
|
||||
|
||||
public static InterestIncentivesFields createNew(final Integer entityType, final Integer attributeName, final Integer conditionType,
|
||||
final String attributeValue, final Integer incentiveType, final BigDecimal amount,
|
||||
final DataValidatorBuilder baseDataValidator) {
|
||||
return new InterestIncentivesFields(entityType, attributeName, conditionType, attributeValue, incentiveType, amount,
|
||||
baseDataValidator);
|
||||
}
|
||||
|
||||
private InterestIncentivesFields(final Integer entityType, final Integer attributeName, final Integer conditionType,
|
||||
final String attributeValue, final Integer incentiveType, final BigDecimal amount,
|
||||
final DataValidatorBuilder baseDataValidator) {
|
||||
this.entityType = entityType;
|
||||
this.attributeName = attributeName;
|
||||
this.attributeValue = attributeValue;
|
||||
this.conditionType = conditionType;
|
||||
this.incentiveType = incentiveType;
|
||||
this.amount = amount;
|
||||
validateIncentiveData(baseDataValidator);
|
||||
}
|
||||
|
||||
public InterestIncentiveAttributeName attributeName() {
|
||||
return InterestIncentiveAttributeName.fromInt(this.attributeName);
|
||||
}
|
||||
|
||||
public ConditionType conditionType() {
|
||||
return ConditionType.fromInt(this.conditionType);
|
||||
}
|
||||
|
||||
public String attributeValue() {
|
||||
return this.attributeValue;
|
||||
}
|
||||
|
||||
public InterestIncentiveType incentiveType() {
|
||||
return InterestIncentiveType.fromInt(this.incentiveType);
|
||||
}
|
||||
|
||||
public BigDecimal amount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public InterestIncentiveEntityType entiryType() {
|
||||
return InterestIncentiveEntityType.fromInt(this.entityType);
|
||||
}
|
||||
|
||||
public void update(final JsonCommand command, final Map<String, Object> actualChanges, final DataValidatorBuilder baseDataValidator,
|
||||
final Locale locale) {
|
||||
if (command.isChangeInIntegerParameterNamed(entityTypeParamName, this.entityType, locale)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(entityTypeParamName, locale);
|
||||
actualChanges.put(entityTypeParamName, newValue);
|
||||
this.entityType = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(attributeNameParamName, this.attributeName, locale)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(attributeNameParamName, locale);
|
||||
actualChanges.put(attributeNameParamName, newValue);
|
||||
this.attributeName = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(conditionTypeParamName, this.conditionType, locale)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(conditionTypeParamName, locale);
|
||||
actualChanges.put(conditionTypeParamName, newValue);
|
||||
this.conditionType = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInStringParameterNamed(attributeValueParamName, this.attributeValue)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(attributeValueParamName);
|
||||
actualChanges.put(attributeValueParamName, newValue);
|
||||
this.attributeValue = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(incentiveTypeparamName, this.incentiveType, locale)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(incentiveTypeparamName, locale);
|
||||
actualChanges.put(incentiveTypeparamName, newValue);
|
||||
this.incentiveType = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed(amountParamName, this.amount, locale)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(amountParamName, locale);
|
||||
actualChanges.put(amountParamName, newValue);
|
||||
this.amount = newValue;
|
||||
}
|
||||
|
||||
validateIncentiveData(baseDataValidator);
|
||||
|
||||
}
|
||||
|
||||
public void validateIncentiveData(final DataValidatorBuilder baseDataValidator) {
|
||||
|
||||
switch (attributeName()) {
|
||||
case GENDER:
|
||||
baseDataValidator.reset().parameter(attributeValueParamName).value(this.attributeValue).longGreaterThanZero();
|
||||
baseDataValidator.reset().parameter(conditionTypeParamName).value(this.conditionType)
|
||||
.isOneOfTheseValues(ConditionType.EQUAL.getValue(), ConditionType.NOT_EQUAL.getValue());
|
||||
break;
|
||||
case AGE:
|
||||
baseDataValidator.reset().parameter(attributeValueParamName).value(this.attributeValue).longGreaterThanZero();
|
||||
break;
|
||||
case CLIENT_CLASSIFICATION:
|
||||
baseDataValidator.reset().parameter(attributeValueParamName).value(this.attributeValue).longGreaterThanZero();
|
||||
baseDataValidator.reset().parameter(conditionTypeParamName).value(this.conditionType)
|
||||
.isOneOfTheseValues(ConditionType.EQUAL.getValue(), ConditionType.NOT_EQUAL.getValue());
|
||||
break;
|
||||
case CLIENT_TYPE:
|
||||
baseDataValidator.reset().parameter(attributeValueParamName).value(this.attributeValue).longGreaterThanZero();
|
||||
baseDataValidator.reset().parameter(conditionTypeParamName).value(this.conditionType)
|
||||
.isOneOfTheseValues(ConditionType.EQUAL.getValue(), ConditionType.NOT_EQUAL.getValue());
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+341
@@ -0,0 +1,341 @@
|
||||
/**
|
||||
* 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.interestratechart.domain;
|
||||
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.INTERESTRATE_CHART_RESOURCE_NAME;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.deleteParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.descriptionParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.idParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.amountRangeFromParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.amountRangeToParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.annualInterestRateParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.fromPeriodParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.periodTypeParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.toPeriodParamName;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants;
|
||||
import org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants;
|
||||
import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_interest_rate_chart")
|
||||
public class InterestRateChart extends AbstractPersistableCustom {
|
||||
|
||||
@Embedded
|
||||
private InterestRateChartFields chartFields;
|
||||
|
||||
@OneToMany(mappedBy = "interestRateChart", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private Set<InterestRateChartSlab> chartSlabs = new HashSet<>();
|
||||
|
||||
protected InterestRateChart() {
|
||||
//
|
||||
}
|
||||
|
||||
public static InterestRateChart createNew(InterestRateChartFields chartFields,
|
||||
Collection<InterestRateChartSlab> interestRateChartSlabs) {
|
||||
|
||||
return new InterestRateChart(chartFields, new HashSet<>(interestRateChartSlabs));
|
||||
}
|
||||
|
||||
private InterestRateChart(InterestRateChartFields chartFields, Set<InterestRateChartSlab> interestRateChartSlabs) {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(INTERESTRATE_CHART_RESOURCE_NAME);
|
||||
this.chartFields = chartFields;
|
||||
// validate before setting the other fields
|
||||
this.validateChartSlabs(baseDataValidator);
|
||||
this.throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
|
||||
this.addChartSlabs(interestRateChartSlabs);
|
||||
|
||||
}
|
||||
|
||||
public void validateChartSlabs(DataValidatorBuilder baseDataValidator) {
|
||||
Collection<InterestRateChartSlab> chartSlabs = this.setOfChartSlabs();
|
||||
|
||||
Integer tmpPeriodType = null;
|
||||
List<InterestRateChartSlab> chartSlabsList = new ArrayList<>(chartSlabs);
|
||||
boolean isPrimaryGroupingByAmount = this.chartFields.isPrimaryGroupingByAmount();
|
||||
chartSlabsList.sort(new InterestRateChartSlabComparator<InterestRateChartSlab>(isPrimaryGroupingByAmount));
|
||||
boolean isPeriodChart = !isPrimaryGroupingByAmount;
|
||||
boolean isAmountChart = isPrimaryGroupingByAmount;
|
||||
|
||||
for (int i = 0; i < chartSlabsList.size(); i++) {
|
||||
InterestRateChartSlab iSlabs = chartSlabsList.get(i);
|
||||
if (!iSlabs.slabFields().isValidChart(isPrimaryGroupingByAmount)) {
|
||||
if (isPrimaryGroupingByAmount) {
|
||||
baseDataValidator.parameter(InterestRateChartSlabApiConstants.amountRangeFromParamName).failWithCode("cannot.be.blank");
|
||||
} else {
|
||||
baseDataValidator.parameter(InterestRateChartSlabApiConstants.fromPeriodParamName).failWithCode("cannot.be.blank");
|
||||
}
|
||||
|
||||
} else if (i > 0) {
|
||||
if (isPeriodChart ^ iSlabs.slabFields().fromPeriod() != null) {
|
||||
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.period.range.incomplete");
|
||||
isPeriodChart = isPeriodChart || iSlabs.slabFields().fromPeriod() != null;
|
||||
}
|
||||
if (isAmountChart ^ iSlabs.slabFields().getAmountRangeFrom() != null) {
|
||||
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.amount.range.incomplete");
|
||||
isAmountChart = isAmountChart || iSlabs.slabFields().getAmountRangeFrom() != null;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
tmpPeriodType = iSlabs.slabFields().periodType();
|
||||
if (iSlabs.slabFields().isNotProperChartStart()) {
|
||||
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.range.start.incorrect",
|
||||
iSlabs.slabFields().fromPeriod(), iSlabs.slabFields().getAmountRangeFrom());
|
||||
}
|
||||
isAmountChart = isAmountChart || iSlabs.slabFields().getAmountRangeFrom() != null;
|
||||
isPeriodChart = isPeriodChart || iSlabs.slabFields().fromPeriod() != null;
|
||||
} else if (iSlabs.slabFields().periodType() != null && !iSlabs.slabFields().periodType().equals(tmpPeriodType)) {
|
||||
baseDataValidator.parameter(periodTypeParamName).value(iSlabs.slabFields().periodType())
|
||||
.failWithCode("period.type.is.not.same", tmpPeriodType);
|
||||
}
|
||||
if (i + 1 < chartSlabsList.size()) {
|
||||
InterestRateChartSlab nextSlabs = chartSlabsList.get(i + 1);
|
||||
if (iSlabs.slabFields().isValidChart(isPrimaryGroupingByAmount)
|
||||
&& nextSlabs.slabFields().isValidChart(isPrimaryGroupingByAmount)) {
|
||||
if (iSlabs.slabFields().isRateChartOverlapping(nextSlabs.slabFields(), isPrimaryGroupingByAmount)) {
|
||||
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.range.overlapping",
|
||||
iSlabs.slabFields().fromPeriod(), iSlabs.slabFields().toPeriod(), nextSlabs.slabFields().fromPeriod(),
|
||||
nextSlabs.slabFields().toPeriod(), iSlabs.slabFields().getAmountRangeFrom(),
|
||||
iSlabs.slabFields().getAmountRangeTo(), nextSlabs.slabFields().getAmountRangeFrom(),
|
||||
nextSlabs.slabFields().getAmountRangeTo());
|
||||
} else if (iSlabs.slabFields().isRateChartHasGap(nextSlabs.slabFields(), isPrimaryGroupingByAmount)) {
|
||||
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.range.has.gap",
|
||||
iSlabs.slabFields().fromPeriod(), iSlabs.slabFields().toPeriod(), nextSlabs.slabFields().fromPeriod(),
|
||||
nextSlabs.slabFields().toPeriod(), iSlabs.slabFields().getAmountRangeFrom(),
|
||||
iSlabs.slabFields().getAmountRangeTo(), nextSlabs.slabFields().getAmountRangeFrom(),
|
||||
nextSlabs.slabFields().getAmountRangeTo());
|
||||
}
|
||||
if (isPrimaryGroupingByAmount) {
|
||||
if (!iSlabs.slabFields().isAmountSame(nextSlabs.slabFields())) {
|
||||
if (InterestRateChartSlabFields.isNotProperPeriodStart(nextSlabs.slabFields())) {
|
||||
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.period.range.start.incorrect",
|
||||
nextSlabs.slabFields().toPeriod());
|
||||
}
|
||||
if (iSlabs.slabFields().toPeriod() != null) {
|
||||
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.period.range.end.incorrect",
|
||||
iSlabs.slabFields().toPeriod());
|
||||
}
|
||||
|
||||
}
|
||||
} else if (!iSlabs.slabFields().isPeriodsSame(nextSlabs.slabFields())) {
|
||||
if (InterestRateChartSlabFields.isNotProperAmountStart(nextSlabs.slabFields())) {
|
||||
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.amount.range.start.incorrect",
|
||||
nextSlabs.slabFields().getAmountRangeFrom());
|
||||
}
|
||||
if (iSlabs.slabFields().getAmountRangeTo() != null) {
|
||||
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.amount.range.end.incorrect",
|
||||
iSlabs.slabFields().getAmountRangeTo());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} else if (iSlabs.slabFields().isNotProperPriodEnd()) {
|
||||
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.range.end.incorrect", iSlabs.slabFields().toPeriod(),
|
||||
iSlabs.slabFields().getAmountRangeTo());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addChartSlabs(Collection<InterestRateChartSlab> interestRateChartSlabsSet) {
|
||||
Set<InterestRateChartSlab> existingChartSlabs = setOfChartSlabs();
|
||||
for (InterestRateChartSlab newChartSlabs : interestRateChartSlabsSet) {
|
||||
newChartSlabs.setInterestRateChart(this);
|
||||
existingChartSlabs.add(newChartSlabs);
|
||||
}
|
||||
}
|
||||
|
||||
public void addChartSlab(InterestRateChartSlab newChartSlab) {
|
||||
newChartSlab.setInterestRateChart(this);
|
||||
setOfChartSlabs().add(newChartSlab);
|
||||
}
|
||||
|
||||
public Set<InterestRateChartSlab> setOfChartSlabs() {
|
||||
if (this.chartSlabs == null) {
|
||||
this.chartSlabs = new HashSet<>();
|
||||
}
|
||||
return this.chartSlabs;
|
||||
}
|
||||
|
||||
public void update(JsonCommand command, final Map<String, Object> actualChanges) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(INTERESTRATE_CHART_RESOURCE_NAME);
|
||||
|
||||
this.update(command, actualChanges, baseDataValidator, null, null);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
|
||||
}
|
||||
|
||||
public void update(JsonCommand command, final Map<String, Object> actualChanges, final DataValidatorBuilder baseDataValidator,
|
||||
final Set<InterestRateChart> existingCharts, String currencyCode) {
|
||||
|
||||
this.chartFields.update(command, actualChanges, baseDataValidator);
|
||||
|
||||
// interestRateChartSlabs
|
||||
if (command.hasParameter(InterestRateChartApiConstants.chartSlabs)) {
|
||||
updateChartSlabs(command, actualChanges, baseDataValidator, currencyCode);
|
||||
}
|
||||
|
||||
this.validateCharts(baseDataValidator, existingCharts);
|
||||
}
|
||||
|
||||
private void validateCharts(final DataValidatorBuilder baseDataValidator, final Set<InterestRateChart> existingCharts) {
|
||||
|
||||
for (InterestRateChart existingChart : existingCharts) {
|
||||
if (!existingChart.equals(this)) {
|
||||
if (this.chartFields.isOverlapping(existingChart.chartFields)) {
|
||||
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.overlapping.from.and.end.dates",
|
||||
existingChart.getFromDate(), existingChart.getEndDate(), this.getFromDate(), this.getEndDate());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateChartSlabs(JsonCommand command, final Map<String, Object> actualChanges, final DataValidatorBuilder baseDataValidator,
|
||||
String currencyCode) {
|
||||
|
||||
final Map<String, Object> deleteChartSlabs = new HashMap<>();
|
||||
final Map<String, Object> chartSlabsChanges = new HashMap<>();
|
||||
final Locale locale = command.extractLocale();
|
||||
if (command.hasParameter(InterestRateChartApiConstants.chartSlabs)) {
|
||||
final JsonArray array = command.arrayOfParameterNamed(InterestRateChartApiConstants.chartSlabs);
|
||||
if (array != null) {
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
final JsonObject chartSlabsElement = array.get(i).getAsJsonObject();
|
||||
JsonCommand chartSlabsCommand = JsonCommand.fromExistingCommand(command, chartSlabsElement);
|
||||
if (chartSlabsCommand.parameterExists(idParamName)) {
|
||||
final Long chartSlabId = chartSlabsCommand.longValueOfParameterNamed(idParamName);
|
||||
final InterestRateChartSlab chartSlab = this.findChartSlab(chartSlabId);
|
||||
if (chartSlab == null) {
|
||||
baseDataValidator.parameter(idParamName).value(chartSlabId).failWithCode("no.chart.slab.associated.with.id");
|
||||
} else if (chartSlabsCommand.parameterExists(deleteParamName)) {
|
||||
if (this.removeChartSlab(chartSlab)) {
|
||||
deleteChartSlabs.put(idParamName, chartSlabId);
|
||||
}
|
||||
} else {
|
||||
chartSlab.update(chartSlabsCommand, chartSlabsChanges, baseDataValidator, locale);
|
||||
}
|
||||
} else {
|
||||
|
||||
/**
|
||||
* TODO: AA: Move this code to InterestRateChartSlabAssembler
|
||||
*/
|
||||
final String description = chartSlabsCommand.stringValueOfParameterNamed(descriptionParamName);
|
||||
final Integer periodTypeId = chartSlabsCommand.integerValueOfParameterNamed(periodTypeParamName, locale);
|
||||
final SavingsPeriodFrequencyType periodFrequencyType = SavingsPeriodFrequencyType.fromInt(periodTypeId);
|
||||
final Integer fromPeriod = chartSlabsCommand.integerValueOfParameterNamed(fromPeriodParamName, locale);
|
||||
final Integer toPeriod = chartSlabsCommand.integerValueOfParameterNamed(toPeriodParamName, locale);
|
||||
final BigDecimal amountRangeFrom = chartSlabsCommand.bigDecimalValueOfParameterNamed(amountRangeFromParamName,
|
||||
locale);
|
||||
final BigDecimal amountRangeTo = chartSlabsCommand.bigDecimalValueOfParameterNamed(amountRangeToParamName, locale);
|
||||
final BigDecimal annualInterestRate = chartSlabsCommand.bigDecimalValueOfParameterNamed(annualInterestRateParamName,
|
||||
locale);
|
||||
|
||||
final InterestRateChartSlabFields slabFields = InterestRateChartSlabFields.createNew(description,
|
||||
periodFrequencyType, fromPeriod, toPeriod, amountRangeFrom, amountRangeTo, annualInterestRate,
|
||||
currencyCode);
|
||||
final InterestRateChartSlab chartSlab = InterestRateChartSlab.createNew(slabFields, this);
|
||||
chartSlab.slabFields().validateChartSlabPlatformRules(chartSlabsCommand, baseDataValidator, locale);
|
||||
chartSlab.updateIncentives(chartSlabsCommand, actualChanges, baseDataValidator, chartSlab, locale);
|
||||
this.addChartSlab(chartSlab);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add chart slab changes to actual changes list.
|
||||
if (!chartSlabsChanges.isEmpty()) {
|
||||
actualChanges.put(InterestRateChartApiConstants.chartSlabs, chartSlabsChanges);
|
||||
}
|
||||
|
||||
// add deleted chart Slabs to actual changes
|
||||
if (!deleteChartSlabs.isEmpty()) {
|
||||
actualChanges.put("deletedChartSlabs", deleteChartSlabs);
|
||||
}
|
||||
|
||||
this.validateChartSlabs(baseDataValidator);
|
||||
}
|
||||
|
||||
public InterestRateChartSlab findChartSlab(Long chartSlabId) {
|
||||
final Set<InterestRateChartSlab> chartSlabs = setOfChartSlabs();
|
||||
|
||||
for (InterestRateChartSlab interestRateChartSlab : chartSlabs) {
|
||||
if (interestRateChartSlab.getId().equals(chartSlabId)) {
|
||||
return interestRateChartSlab;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean removeChartSlab(InterestRateChartSlab chartSlab) {
|
||||
final Set<InterestRateChartSlab> chartSlabs = setOfChartSlabs();
|
||||
return chartSlabs.remove(chartSlab);
|
||||
}
|
||||
|
||||
public LocalDate getFromDate() {
|
||||
return this.chartFields.getFromDate();
|
||||
}
|
||||
|
||||
public LocalDate getEndDate() {
|
||||
return this.chartFields.getEndDate();
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
public InterestRateChartFields chartFields() {
|
||||
return this.chartFields;
|
||||
}
|
||||
|
||||
public boolean isApplicableChartFor(final LocalDate target) {
|
||||
return this.chartFields.isApplicableChartFor(target);
|
||||
}
|
||||
}
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* 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.interestratechart.domain;
|
||||
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.dateFormatParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.descriptionParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.endDateParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.fromDateParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.isPrimaryGroupingByAmountParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.localeParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.nameParamName;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.domain.LocalDateInterval;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
|
||||
@Embeddable
|
||||
public class InterestRateChartFields {
|
||||
|
||||
@Column(name = "name", length = 100, unique = false, nullable = false)
|
||||
private String name;
|
||||
|
||||
@Column(name = "description", nullable = true)
|
||||
private String description;
|
||||
|
||||
@Column(name = "from_date", nullable = false)
|
||||
private LocalDate fromDate;
|
||||
|
||||
@Column(name = "end_date", nullable = true)
|
||||
private LocalDate endDate;
|
||||
|
||||
@Column(name = "is_primary_grouping_by_amount", nullable = false)
|
||||
private boolean isPrimaryGroupingByAmount;
|
||||
|
||||
protected InterestRateChartFields() {
|
||||
//
|
||||
}
|
||||
|
||||
public static InterestRateChartFields createNew(String name, String description, LocalDate fromDate, LocalDate toDate,
|
||||
boolean isPrimaryGroupingByAmount) {
|
||||
return new InterestRateChartFields(name, description, fromDate, toDate, isPrimaryGroupingByAmount);
|
||||
}
|
||||
|
||||
private InterestRateChartFields(String name, String description, LocalDate fromDate, LocalDate toDate,
|
||||
boolean isPrimaryGroupingByAmount) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.fromDate = fromDate;
|
||||
this.endDate = toDate;
|
||||
this.isPrimaryGroupingByAmount = isPrimaryGroupingByAmount;
|
||||
}
|
||||
|
||||
public void update(JsonCommand command, final Map<String, Object> actualChanges, final DataValidatorBuilder baseDataValidator) {
|
||||
|
||||
if (command.isChangeInStringParameterNamed(nameParamName, this.name)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(nameParamName);
|
||||
actualChanges.put(nameParamName, newValue);
|
||||
this.name = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInStringParameterNamed(descriptionParamName, this.description)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(descriptionParamName);
|
||||
actualChanges.put(descriptionParamName, newValue);
|
||||
this.description = newValue;
|
||||
}
|
||||
|
||||
final String localeAsInput = command.locale();
|
||||
final String dateFormat = command.dateFormat();
|
||||
|
||||
if (command.isChangeInLocalDateParameterNamed(fromDateParamName, getFromDate())) {
|
||||
final String newValueAsString = command.stringValueOfParameterNamed(fromDateParamName);
|
||||
actualChanges.put(fromDateParamName, newValueAsString);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
actualChanges.put(dateFormatParamName, dateFormat);
|
||||
this.fromDate = command.localDateValueOfParameterNamed(fromDateParamName);
|
||||
}
|
||||
|
||||
if (command.isChangeInLocalDateParameterNamed(endDateParamName, getEndDate())) {
|
||||
final String newValueAsString = command.stringValueOfParameterNamed(endDateParamName);
|
||||
actualChanges.put(endDateParamName, newValueAsString);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
actualChanges.put(dateFormatParamName, dateFormat);
|
||||
this.endDate = command.localDateValueOfParameterNamed(endDateParamName);
|
||||
}
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(isPrimaryGroupingByAmountParamName, this.isPrimaryGroupingByAmount)) {
|
||||
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(isPrimaryGroupingByAmountParamName);
|
||||
actualChanges.put(isPrimaryGroupingByAmountParamName, newValue);
|
||||
this.isPrimaryGroupingByAmount = newValue;
|
||||
}
|
||||
|
||||
if (isFromDateAfterToDate()) {
|
||||
baseDataValidator.parameter(fromDateParamName).value(fromDate).failWithCode("from.date.is.after.to.date");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFromDateAfterToDate() {
|
||||
return isFromDateAfter(getEndDate());
|
||||
}
|
||||
|
||||
public boolean isFromDateAfter(LocalDate compare) {
|
||||
return compare != null && DateUtils.isAfter(getFromDate(), compare);
|
||||
}
|
||||
|
||||
public LocalDate getFromDate() {
|
||||
return this.fromDate;
|
||||
}
|
||||
|
||||
public LocalDate getEndDate() {
|
||||
return this.endDate;
|
||||
}
|
||||
|
||||
public boolean isOverlapping(InterestRateChartFields that) {
|
||||
final LocalDate thisFromDate = this.getFromDate();
|
||||
LocalDate thisEndDate = this.getEndDate();
|
||||
thisEndDate = thisEndDate == null ? DateUtils.getBusinessLocalDate() : thisEndDate;
|
||||
final LocalDate thatFromDate = that.getFromDate();
|
||||
LocalDate thatEndDate = that.getEndDate();
|
||||
thatEndDate = thatEndDate == null ? DateUtils.getBusinessLocalDate() : thatEndDate;
|
||||
|
||||
final LocalDateInterval thisInterval = LocalDateInterval.create(thisFromDate, thisEndDate);
|
||||
final LocalDateInterval thatInterval = LocalDateInterval.create(thatFromDate, thatEndDate);
|
||||
|
||||
if (thisInterval.containsPortionOf(thatInterval) || thatInterval.containsPortionOf(thisInterval)) {
|
||||
return true;
|
||||
}
|
||||
return false;// no overlapping
|
||||
}
|
||||
|
||||
public boolean isApplicableChartFor(final LocalDate target) {
|
||||
final LocalDate endDate = this.endDate == null ? DateUtils.getBusinessLocalDate() : this.getEndDate();
|
||||
final LocalDateInterval interval = LocalDateInterval.create(getFromDate(), endDate);
|
||||
return interval.contains(target);
|
||||
}
|
||||
|
||||
public boolean isPrimaryGroupingByAmount() {
|
||||
return this.isPrimaryGroupingByAmount;
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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.interestratechart.domain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
public interface InterestRateChartRepository extends JpaRepository<InterestRateChart, Long>, JpaSpecificationExecutor<InterestRateChart> {
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* 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.interestratechart.domain;
|
||||
|
||||
import org.apache.fineract.portfolio.interestratechart.exception.InterestRateChartNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Wrapper for {@link InterestRateChartRepository} that is responsible for checking if {@link InterestRateChart} is
|
||||
* returned when using <code>findOne</code> repository method and throwing an appropriate not found exception.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This is to avoid need for checking and throwing in multiple areas of code base where
|
||||
* {@link InterestRateChartRepository} is required.
|
||||
* </p>
|
||||
*/
|
||||
@Service
|
||||
public class InterestRateChartRepositoryWrapper {
|
||||
|
||||
private final InterestRateChartRepository repository;
|
||||
|
||||
@Autowired
|
||||
public InterestRateChartRepositoryWrapper(final InterestRateChartRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public InterestRateChart findOneWithNotFoundDetection(final Long intrestRateChartId) {
|
||||
return this.repository.findById(intrestRateChartId).orElseThrow(() -> new InterestRateChartNotFoundException(intrestRateChartId));
|
||||
}
|
||||
|
||||
public void save(final InterestRateChart interestRateChart) {
|
||||
this.repository.save(interestRateChart);
|
||||
}
|
||||
|
||||
public void delete(final InterestRateChart interestRateChart) {
|
||||
this.repository.delete(interestRateChart);
|
||||
}
|
||||
|
||||
public void saveAndFlush(final InterestRateChart interestRateChart) {
|
||||
this.repository.saveAndFlush(interestRateChart);
|
||||
}
|
||||
}
|
||||
+196
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* 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.interestratechart.domain;
|
||||
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.amountParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.attributeNameParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.attributeValueParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.conditionTypeParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.entityTypeParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.incentiveTypeparamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.deleteParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.idParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.INTERESTRATE_CHART_SLAB_RESOURCE_NAME;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants;
|
||||
import org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_interest_rate_slab")
|
||||
public class InterestRateChartSlab extends AbstractPersistableCustom {
|
||||
|
||||
@Embedded
|
||||
private InterestRateChartSlabFields slabFields;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "interest_rate_chart_id", referencedColumnName = "id", nullable = false)
|
||||
private InterestRateChart interestRateChart;
|
||||
|
||||
@OneToMany(mappedBy = "interestRateChartSlab", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private Set<InterestIncentives> interestIncentives = new HashSet<>();
|
||||
|
||||
protected InterestRateChartSlab() {
|
||||
//
|
||||
}
|
||||
|
||||
public static InterestRateChartSlab createNew(InterestRateChartSlabFields slabFields, InterestRateChart interestRateChart) {
|
||||
return new InterestRateChartSlab(slabFields, interestRateChart);
|
||||
}
|
||||
|
||||
public void update(JsonCommand command, final Map<String, Object> actualChanges, final Locale locale) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(INTERESTRATE_CHART_SLAB_RESOURCE_NAME);
|
||||
this.update(command, actualChanges, baseDataValidator, locale);
|
||||
this.interestRateChart.validateChartSlabs(baseDataValidator);
|
||||
this.throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
public void update(JsonCommand command, final Map<String, Object> actualChanges, final DataValidatorBuilder baseDataValidator,
|
||||
final Locale locale) {
|
||||
this.slabFields.update(command, actualChanges, baseDataValidator, locale);
|
||||
updateIncentives(command, actualChanges, baseDataValidator, this, locale);
|
||||
}
|
||||
|
||||
private InterestRateChartSlab(InterestRateChartSlabFields slabFields, InterestRateChart interestRateChart) {
|
||||
|
||||
this.slabFields = slabFields;
|
||||
this.interestRateChart = interestRateChart;
|
||||
if (this.interestRateChart != null) {
|
||||
interestRateChart.addChartSlab(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void setInterestRateChart(InterestRateChart interestRateChart) {
|
||||
this.interestRateChart = interestRateChart;
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
public InterestRateChartSlabFields slabFields() {
|
||||
return this.slabFields;
|
||||
}
|
||||
|
||||
public Set<InterestIncentives> setOfInterestIncentives() {
|
||||
if (this.interestIncentives == null) {
|
||||
this.interestIncentives = new HashSet<>();
|
||||
}
|
||||
return this.interestIncentives;
|
||||
}
|
||||
|
||||
public void addInterestIncentive(InterestIncentives interestIncentives) {
|
||||
interestIncentives.updateInterestRateChartSlab(this);
|
||||
setOfInterestIncentives().add(interestIncentives);
|
||||
}
|
||||
|
||||
public InterestIncentives findInterestIncentive(Long interestIncentiveId) {
|
||||
final Set<InterestIncentives> interestIncentives = setOfInterestIncentives();
|
||||
|
||||
for (InterestIncentives interestIncentive : interestIncentives) {
|
||||
if (interestIncentive.getId().equals(interestIncentiveId)) {
|
||||
return interestIncentive;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean removeInterestIncentive(InterestIncentives incentive) {
|
||||
final Set<InterestIncentives> incentives = setOfInterestIncentives();
|
||||
return incentives.remove(incentive);
|
||||
}
|
||||
|
||||
public void updateIncentives(JsonCommand command, final Map<String, Object> actualChanges, final DataValidatorBuilder baseDataValidator,
|
||||
final InterestRateChartSlab chartSlab, final Locale locale) {
|
||||
final Map<String, Object> deleteIncentives = new HashMap<>();
|
||||
final Map<String, Object> IncentiveChanges = new HashMap<>();
|
||||
if (command.hasParameter(InterestRateChartSlabApiConstants.incentivesParamName)) {
|
||||
final JsonArray array = command.arrayOfParameterNamed(InterestRateChartSlabApiConstants.incentivesParamName);
|
||||
if (array != null) {
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
final JsonObject incentiveElement = array.get(i).getAsJsonObject();
|
||||
JsonCommand incentivesCommand = JsonCommand.fromExistingCommand(command, incentiveElement);
|
||||
if (incentivesCommand.parameterExists(InterestIncentiveApiConstants.idParamName)) {
|
||||
final Long interestIncentiveId = incentivesCommand
|
||||
.longValueOfParameterNamed(InterestIncentiveApiConstants.idParamName);
|
||||
final InterestIncentives interestIncentives = chartSlab.findInterestIncentive(interestIncentiveId);
|
||||
if (interestIncentives == null) {
|
||||
baseDataValidator.parameter(InterestIncentiveApiConstants.idParamName).value(interestIncentiveId)
|
||||
.failWithCode("no.interest.incentive.associated.with.id");
|
||||
} else if (incentivesCommand.parameterExists(deleteParamName)) {
|
||||
if (chartSlab.removeInterestIncentive(interestIncentives)) {
|
||||
deleteIncentives.put(idParamName, interestIncentiveId);
|
||||
}
|
||||
} else {
|
||||
interestIncentives.update(incentivesCommand, IncentiveChanges, baseDataValidator, locale);
|
||||
}
|
||||
} else {
|
||||
Integer entityType = incentivesCommand.integerValueOfParameterNamed(entityTypeParamName, locale);
|
||||
Integer conditionType = incentivesCommand.integerValueOfParameterNamed(conditionTypeParamName, locale);
|
||||
Integer attributeName = incentivesCommand.integerValueOfParameterNamed(attributeNameParamName, locale);
|
||||
String attributeValue = incentivesCommand.stringValueOfParameterNamed(attributeValueParamName);
|
||||
Integer incentiveType = incentivesCommand.integerValueOfParameterNamed(incentiveTypeparamName, locale);
|
||||
BigDecimal amount = incentivesCommand.bigDecimalValueOfParameterNamed(amountParamName, locale);
|
||||
InterestIncentivesFields incentivesFields = InterestIncentivesFields.createNew(entityType, attributeName,
|
||||
conditionType, attributeValue, incentiveType, amount, baseDataValidator);
|
||||
InterestIncentives incentives = new InterestIncentives(chartSlab, incentivesFields);
|
||||
chartSlab.addInterestIncentive(incentives);
|
||||
}
|
||||
}
|
||||
}
|
||||
// add chart slab changes to actual changes list.
|
||||
if (!IncentiveChanges.isEmpty()) {
|
||||
actualChanges.put(InterestRateChartSlabApiConstants.incentivesParamName, IncentiveChanges);
|
||||
}
|
||||
|
||||
// add deleted chart Slabs to actual changes
|
||||
if (!deleteIncentives.isEmpty()) {
|
||||
actualChanges.put("deletedIncentives", deleteIncentives);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 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.interestratechart.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Comparator;
|
||||
import org.apache.fineract.portfolio.savings.domain.DepositAccountInterestRateChartSlabs;
|
||||
|
||||
/**
|
||||
* Sort InterestRateChartSlab by input range
|
||||
*/
|
||||
public class InterestRateChartSlabComparator<T> implements Comparator<T> {
|
||||
|
||||
private final boolean isPrimaryGroupingByAmount;
|
||||
|
||||
public InterestRateChartSlabComparator(final boolean isPrimaryGroupingByAmount) {
|
||||
this.isPrimaryGroupingByAmount = isPrimaryGroupingByAmount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(final T o1, final T o2) {
|
||||
int compareResult = 0;
|
||||
InterestRateChartSlabFields slabs1 = null;
|
||||
InterestRateChartSlabFields slabs2 = null;
|
||||
if (o1 instanceof InterestRateChartSlab) {
|
||||
slabs1 = ((InterestRateChartSlab) o1).slabFields();
|
||||
slabs2 = ((InterestRateChartSlab) o2).slabFields();
|
||||
} else if (o1 instanceof DepositAccountInterestRateChartSlabs) {
|
||||
slabs1 = ((DepositAccountInterestRateChartSlabs) o1).slabFields();
|
||||
slabs2 = ((DepositAccountInterestRateChartSlabs) o2).slabFields();
|
||||
} else {
|
||||
return compareResult;
|
||||
}
|
||||
|
||||
if (slabs1.isPeriodsSame(slabs2) && slabs1.isAmountSame(slabs2)) {
|
||||
compareResult = 0;
|
||||
} else {
|
||||
if (isPrimaryGroupingByAmount) {
|
||||
if (slabs1.isAmountSame(slabs2)) {
|
||||
compareResult = comparePeriods(slabs1, slabs2);
|
||||
} else {
|
||||
compareResult = compareAmounts(slabs1, slabs2);
|
||||
}
|
||||
} else {
|
||||
if (slabs1.isPeriodsSame(slabs2)) {
|
||||
compareResult = compareAmounts(slabs1, slabs2);
|
||||
} else {
|
||||
compareResult = comparePeriods(slabs1, slabs2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return compareResult;
|
||||
}
|
||||
|
||||
private int comparePeriods(final InterestRateChartSlabFields slabs1, InterestRateChartSlabFields slabs2) {
|
||||
int compareResult = 0;
|
||||
Integer periodFrom1 = slabs1.fromPeriod();
|
||||
Integer periodFrom2 = slabs2.fromPeriod();
|
||||
if (periodFrom1 != null && periodFrom2 != null) {
|
||||
compareResult = periodFrom1.compareTo(periodFrom2);
|
||||
}
|
||||
return compareResult;
|
||||
}
|
||||
|
||||
private int compareAmounts(final InterestRateChartSlabFields slabs1, InterestRateChartSlabFields slabs2) {
|
||||
int compareResult = 0;
|
||||
BigDecimal amountFrom1 = slabs1.getAmountRangeFrom();
|
||||
BigDecimal amountFrom2 = slabs2.getAmountRangeFrom();
|
||||
if (amountFrom1 != null && amountFrom2 != null) {
|
||||
compareResult = amountFrom1.compareTo(amountFrom2);
|
||||
}
|
||||
return compareResult;
|
||||
}
|
||||
|
||||
}
|
||||
+376
@@ -0,0 +1,376 @@
|
||||
/**
|
||||
* 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.interestratechart.domain;
|
||||
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.amountRangeFromParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.amountRangeToParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.annualInterestRateParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.descriptionParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.fromPeriodParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.periodTypeParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.toPeriodParamName;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Comparator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
|
||||
@Embeddable
|
||||
public class InterestRateChartSlabFields {
|
||||
|
||||
@Column(name = "description", nullable = true)
|
||||
private String description;
|
||||
|
||||
@Column(name = "period_type_enum", nullable = true)
|
||||
private Integer periodType;
|
||||
|
||||
@Column(name = "from_period")
|
||||
private Integer fromPeriod;
|
||||
|
||||
@Column(name = "to_period")
|
||||
private Integer toPeriod;
|
||||
|
||||
@Column(name = "amount_range_from", scale = 6, precision = 19)
|
||||
private BigDecimal amountRangeFrom;
|
||||
|
||||
public BigDecimal getAmountRangeFrom() {
|
||||
return this.amountRangeFrom;
|
||||
}
|
||||
|
||||
public BigDecimal getAmountRangeTo() {
|
||||
return this.amountRangeTo;
|
||||
}
|
||||
|
||||
@Column(name = "amount_range_to", scale = 6, precision = 19)
|
||||
private BigDecimal amountRangeTo;
|
||||
|
||||
@Column(name = "annual_interest_rate", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal annualInterestRate;
|
||||
|
||||
@Column(name = "currency_code", nullable = false)
|
||||
private String currencyCode;
|
||||
|
||||
protected InterestRateChartSlabFields() {
|
||||
//
|
||||
}
|
||||
|
||||
public static InterestRateChartSlabFields createNew(final String description, final SavingsPeriodFrequencyType periodFrequencyType,
|
||||
final Integer fromPeriod, final Integer toPeriod, final BigDecimal amountRangeFrom, final BigDecimal amountRangeTo,
|
||||
final BigDecimal annualInterestRate, final String currencyCode) {
|
||||
return new InterestRateChartSlabFields(description, periodFrequencyType, fromPeriod, toPeriod, amountRangeFrom, amountRangeTo,
|
||||
annualInterestRate, currencyCode);
|
||||
}
|
||||
|
||||
private InterestRateChartSlabFields(final String description, final SavingsPeriodFrequencyType periodFrequencyType,
|
||||
final Integer fromPeriod, final Integer toPeriod, final BigDecimal amountRangeFrom, final BigDecimal amountRangeTo,
|
||||
final BigDecimal annualInterestRate, final String currencyCode) {
|
||||
this.description = description;
|
||||
this.periodType = (periodFrequencyType == null || periodFrequencyType.isInvalid()) ? null : periodFrequencyType.getValue();
|
||||
this.fromPeriod = fromPeriod;
|
||||
this.toPeriod = toPeriod;
|
||||
this.amountRangeFrom = amountRangeFrom;
|
||||
this.amountRangeTo = amountRangeTo;
|
||||
this.annualInterestRate = annualInterestRate;
|
||||
this.currencyCode = currencyCode;
|
||||
}
|
||||
|
||||
public void update(final JsonCommand command, final Map<String, Object> actualChanges, final DataValidatorBuilder baseDataValidator,
|
||||
final Locale locale) {
|
||||
|
||||
if (command.isChangeInStringParameterNamed(descriptionParamName, this.description)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(descriptionParamName);
|
||||
actualChanges.put(descriptionParamName, newValue);
|
||||
this.description = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(periodTypeParamName, this.periodType, locale)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(periodTypeParamName, locale);
|
||||
actualChanges.put(periodTypeParamName, newValue);
|
||||
this.periodType = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(fromPeriodParamName, this.fromPeriod, locale)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(fromPeriodParamName, locale);
|
||||
actualChanges.put(fromPeriodParamName, newValue);
|
||||
this.fromPeriod = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(toPeriodParamName, this.toPeriod, locale)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(toPeriodParamName, locale);
|
||||
actualChanges.put(toPeriodParamName, newValue);
|
||||
this.toPeriod = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed(amountRangeFromParamName, this.amountRangeFrom, locale)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(amountRangeFromParamName, locale);
|
||||
actualChanges.put(amountRangeFromParamName, newValue);
|
||||
this.amountRangeFrom = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed(amountRangeToParamName, this.amountRangeTo, locale)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(amountRangeToParamName, locale);
|
||||
actualChanges.put(amountRangeToParamName, newValue);
|
||||
this.amountRangeTo = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed(annualInterestRateParamName, this.annualInterestRate, locale)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(annualInterestRateParamName, locale);
|
||||
actualChanges.put(annualInterestRateParamName, newValue);
|
||||
this.annualInterestRate = newValue;
|
||||
}
|
||||
|
||||
validateChartSlabPlatformRules(command, baseDataValidator, locale);
|
||||
}
|
||||
|
||||
public void validateChartSlabPlatformRules(final JsonCommand chartSlabsCommand, final DataValidatorBuilder baseDataValidator,
|
||||
Locale locale) {
|
||||
if (isFromPeriodGreaterThanToPeriod()) {
|
||||
final Integer fromPeriod = chartSlabsCommand.integerValueOfParameterNamed(fromPeriodParamName, locale);
|
||||
baseDataValidator.parameter(fromPeriodParamName).value(fromPeriod).failWithCode("from.period.is.greater.than.to.period");
|
||||
}
|
||||
|
||||
if (isAmountRangeFromGreaterThanTo()) {
|
||||
final BigDecimal amountRangeFrom = chartSlabsCommand.bigDecimalValueOfParameterNamed(amountRangeFromParamName, locale);
|
||||
baseDataValidator.parameter(amountRangeFromParamName).value(amountRangeFrom)
|
||||
.failWithCode("amount.range.from.is.greater.than.amount.range.to");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFromPeriodGreaterThanToPeriod() {
|
||||
boolean isGreater = false;
|
||||
if (this.toPeriod != null && this.fromPeriod.compareTo(this.toPeriod) > 0) {
|
||||
isGreater = true;
|
||||
}
|
||||
return isGreater;
|
||||
}
|
||||
|
||||
public boolean isAmountRangeFromGreaterThanTo() {
|
||||
boolean isGreater = false;
|
||||
if (this.amountRangeFrom != null && this.amountRangeTo != null && this.amountRangeFrom.compareTo(this.amountRangeTo) > 0) {
|
||||
isGreater = true;
|
||||
}
|
||||
return isGreater;
|
||||
}
|
||||
|
||||
public Integer periodType() {
|
||||
return this.periodType;
|
||||
}
|
||||
|
||||
public Integer fromPeriod() {
|
||||
return this.fromPeriod;
|
||||
}
|
||||
|
||||
public Integer toPeriod() {
|
||||
return this.toPeriod;
|
||||
}
|
||||
|
||||
public boolean isRateChartHasGap(final InterestRateChartSlabFields that, final boolean isPrimaryGroupingByAmount) {
|
||||
boolean isPeriodSame = isPeriodsSame(that);
|
||||
boolean isAmountSame = isAmountSame(that);
|
||||
boolean hasPeriods = this.fromPeriod != null || that.fromPeriod != null;
|
||||
boolean hasAmounts = this.amountRangeFrom != null || that.amountRangeFrom != null;
|
||||
if (isPrimaryGroupingByAmount) {
|
||||
if (isAmountSame) {
|
||||
if (hasPeriods) {
|
||||
if (this.toPeriod == null) {
|
||||
return true;
|
||||
}
|
||||
return isNotProperPeriodStart(that.fromPeriod);
|
||||
}
|
||||
} else {
|
||||
return isNotProperAmountStart(that.amountRangeFrom) || isNotProperPeriodStart(that);
|
||||
}
|
||||
} else {
|
||||
if (isPeriodSame) {
|
||||
if (hasAmounts) {
|
||||
if (this.amountRangeTo == null) {
|
||||
return true;
|
||||
}
|
||||
return isNotProperAmountStart(that.amountRangeFrom);
|
||||
}
|
||||
} else {
|
||||
return isNotProperPeriodStart(that.fromPeriod) || isNotProperAmountStart(that);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isValidChart(boolean isPrimaryGroupingByAmount) {
|
||||
return (!isPrimaryGroupingByAmount && this.fromPeriod != null) || (isPrimaryGroupingByAmount && this.amountRangeFrom != null);
|
||||
}
|
||||
|
||||
public boolean isNotProperChartStart() {
|
||||
return isNotProperPeriodStart(this) || isNotProperAmountStart(this);
|
||||
}
|
||||
|
||||
public static boolean isNotProperAmountStart(final InterestRateChartSlabFields interestRateChartSlabFields) {
|
||||
return interestRateChartSlabFields.amountRangeFrom != null
|
||||
&& (interestRateChartSlabFields.amountRangeFrom.compareTo(BigDecimal.ONE) != 0
|
||||
&& interestRateChartSlabFields.amountRangeFrom.compareTo(BigDecimal.ZERO) != 0);
|
||||
}
|
||||
|
||||
private boolean isNotProperAmountStart(final BigDecimal amount) {
|
||||
return this.amountRangeTo == null || (amount != null && amount.compareTo(this.amountRangeTo.add(BigDecimal.ONE)) != 0);
|
||||
}
|
||||
|
||||
private boolean isNotProperPeriodStart(final Integer period) {
|
||||
return this.toPeriod == null || (period != null && period.compareTo(this.toPeriod + 1) != 0);
|
||||
}
|
||||
|
||||
public static boolean isNotProperPeriodStart(InterestRateChartSlabFields interestRateChartSlabFields) {
|
||||
return interestRateChartSlabFields.fromPeriod != null
|
||||
&& !(interestRateChartSlabFields.fromPeriod.equals(1) || interestRateChartSlabFields.fromPeriod.equals(0));
|
||||
}
|
||||
|
||||
public boolean isNotProperPriodEnd() {
|
||||
return !(this.toPeriod == null && this.amountRangeTo == null);
|
||||
|
||||
}
|
||||
|
||||
public boolean isRateChartOverlapping(final InterestRateChartSlabFields that, final boolean isPrimaryGroupingByAmount) {
|
||||
boolean isPeriodOverLapping = isPeriodOverlapping(that);
|
||||
boolean isAmountOverLapping = isAmountOverlapping(that);
|
||||
boolean isPeriodSame = isPeriodsSame(that);
|
||||
boolean isAmountSame = isAmountSame(that);
|
||||
boolean isOverlapping = false;
|
||||
if (isPrimaryGroupingByAmount) {
|
||||
isOverlapping = (isAmountOverLapping && !isAmountSame) || (isPeriodOverLapping && isAmountSame);
|
||||
} else {
|
||||
isOverlapping = (isPeriodOverLapping && !isPeriodSame) || (isAmountOverLapping && isPeriodSame);
|
||||
}
|
||||
|
||||
return isOverlapping;
|
||||
}
|
||||
|
||||
private boolean isPeriodOverlapping(final InterestRateChartSlabFields that) {
|
||||
if (isIntegerSame(that.toPeriod, this.toPeriod)) {
|
||||
return true;
|
||||
} else if (isIntegerSame(that.fromPeriod, this.fromPeriod)) {
|
||||
return true;
|
||||
} else if (this.toPeriod == null) {
|
||||
return true;
|
||||
} else if (that.toPeriod == null) {
|
||||
return that.fromPeriod <= this.toPeriod;
|
||||
}
|
||||
return this.fromPeriod <= that.toPeriod && that.fromPeriod <= this.toPeriod;
|
||||
}
|
||||
|
||||
private boolean isAmountOverlapping(final InterestRateChartSlabFields that) {
|
||||
if (isBigDecimalSame(that.amountRangeFrom, this.amountRangeFrom)) {
|
||||
return true;
|
||||
} else if (isBigDecimalSame(that.amountRangeTo, this.amountRangeTo)) {
|
||||
return true;
|
||||
} else if (this.amountRangeTo == null) {
|
||||
return true;
|
||||
} else if (that.amountRangeTo == null) {
|
||||
return that.amountRangeFrom.compareTo(this.amountRangeTo) <= 0;
|
||||
}
|
||||
return this.amountRangeFrom.compareTo(that.amountRangeTo) <= 0 && that.amountRangeFrom.compareTo(this.amountRangeTo) <= 0;
|
||||
}
|
||||
|
||||
public boolean isAmountSame(final InterestRateChartSlabFields that) {
|
||||
return isBigDecimalSame(this.amountRangeFrom, that.amountRangeFrom) && isBigDecimalSame(this.amountRangeTo, that.amountRangeTo);
|
||||
}
|
||||
|
||||
public boolean isPeriodsSame(final InterestRateChartSlabFields that) {
|
||||
return isIntegerSame(this.fromPeriod, that.fromPeriod) && isIntegerSame(this.toPeriod, that.toPeriod);
|
||||
}
|
||||
|
||||
public boolean isIntegerSame(final Integer obj1, final Integer obj2) {
|
||||
if (obj1 == null || obj2 == null) {
|
||||
if (Objects.equals(obj1, obj2)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return obj1.equals(obj2);
|
||||
}
|
||||
|
||||
public boolean isBigDecimalSame(final BigDecimal obj1, final BigDecimal obj2) {
|
||||
if (obj1 == null || obj2 == null) {
|
||||
return Objects.compare(obj1, obj2, Comparator.nullsFirst(Comparator.naturalOrder())) == 0;
|
||||
}
|
||||
return obj1.compareTo(obj2) == 0;
|
||||
}
|
||||
|
||||
public boolean isBetweenPeriod(final LocalDate periodStartDate, final LocalDate periodEndDate) {
|
||||
final Integer compare = depositPeriod(periodStartDate, periodEndDate);
|
||||
return isPeriodBetween(compare);
|
||||
}
|
||||
|
||||
public boolean isAmountRangeProvided() {
|
||||
return this.amountRangeFrom != null;
|
||||
}
|
||||
|
||||
public BigDecimal annualInterestRate() {
|
||||
return this.annualInterestRate;
|
||||
}
|
||||
|
||||
public Integer depositPeriod(final LocalDate periodStartDate, final LocalDate periodEndDate) {
|
||||
Integer actualDepositPeriod = 0;
|
||||
final SavingsPeriodFrequencyType periodFrequencyType = SavingsPeriodFrequencyType.fromInt(periodType());
|
||||
switch (periodFrequencyType) {
|
||||
case DAYS:
|
||||
actualDepositPeriod = Math.toIntExact(ChronoUnit.DAYS.between(periodStartDate, periodEndDate));
|
||||
break;
|
||||
case WEEKS:
|
||||
actualDepositPeriod = Math.toIntExact(ChronoUnit.WEEKS.between(periodStartDate, periodEndDate));
|
||||
break;
|
||||
case MONTHS:
|
||||
actualDepositPeriod = Math.toIntExact(ChronoUnit.MONTHS.between(periodStartDate, periodEndDate));
|
||||
break;
|
||||
case YEARS:
|
||||
actualDepositPeriod = Math.toIntExact(ChronoUnit.YEARS.between(periodStartDate, periodEndDate));
|
||||
break;
|
||||
case INVALID:
|
||||
actualDepositPeriod = 0;// default value
|
||||
break;
|
||||
}
|
||||
return actualDepositPeriod;
|
||||
}
|
||||
|
||||
public boolean isAmountBetween(final BigDecimal depositAmount) {
|
||||
boolean returnValue = true;
|
||||
if (amountRangeFrom != null && amountRangeTo != null) {
|
||||
returnValue = depositAmount.compareTo(amountRangeFrom) >= 0 && depositAmount.compareTo(amountRangeTo) <= 0;
|
||||
} else if (amountRangeFrom != null) {
|
||||
returnValue = depositAmount.compareTo(amountRangeFrom) >= 0;
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
public boolean isPeriodBetween(final Integer periods) {
|
||||
boolean returnValue = true;
|
||||
if (fromPeriod != null && toPeriod != null) {
|
||||
returnValue = periods.compareTo(fromPeriod) >= 0 && periods.compareTo(toPeriod) <= 0;
|
||||
} else if (fromPeriod != null) {
|
||||
returnValue = periods.compareTo(fromPeriod) >= 0;
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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.interestratechart.domain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
public interface InterestRateChartSlabRepository
|
||||
extends JpaRepository<InterestRateChartSlab, Long>, JpaSpecificationExecutor<InterestRateChartSlab> {
|
||||
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* 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.interestratechart.domain;
|
||||
|
||||
import org.apache.fineract.portfolio.interestratechart.exception.InterestRateChartSlabNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Wrapper for {@link InterestRateChartSlabRepository} that is responsible for checking if {@link InterestRateChartSlab}
|
||||
* is returned when using <code>findOne</code> repository method and throwing an appropriate not found exception.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This is to avoid need for checking and throwing in multiple areas of code base where
|
||||
* {@link InterestRateChartSlabRepository} is required.
|
||||
* </p>
|
||||
*/
|
||||
@Service
|
||||
public class InterestRateChartSlabRepositoryWrapper {
|
||||
|
||||
private final InterestRateChartSlabRepository repository;
|
||||
|
||||
@Autowired
|
||||
public InterestRateChartSlabRepositoryWrapper(final InterestRateChartSlabRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public InterestRateChartSlab findOneWithNotFoundDetection(final Long chartSlabId) {
|
||||
return this.repository.findById(chartSlabId).orElseThrow(() -> new InterestRateChartSlabNotFoundException(chartSlabId));
|
||||
}
|
||||
|
||||
public void save(final InterestRateChartSlab chartSlab) {
|
||||
this.repository.save(chartSlab);
|
||||
}
|
||||
|
||||
public void delete(final InterestRateChartSlab chartSlab) {
|
||||
this.repository.delete(chartSlab);
|
||||
}
|
||||
|
||||
public void saveAndFlush(final InterestRateChartSlab chartSlab) {
|
||||
this.repository.saveAndFlush(chartSlab);
|
||||
}
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.interestratechart.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
|
||||
public class InterestRateChartNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||
|
||||
public InterestRateChartNotFoundException(final Long id) {
|
||||
super("error.msg.interest.rate.chart.id.invalid", "Interest rate chart with identifier " + id + " does not exist", id);
|
||||
}
|
||||
|
||||
public InterestRateChartNotFoundException(Long id, EmptyResultDataAccessException e) {
|
||||
super("error.msg.interest.rate.chart.id.invalid", "Interest rate chart with identifier " + id + " does not exist", id, e);
|
||||
}
|
||||
}
|
||||
+34
@@ -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.interestratechart.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
|
||||
public class InterestRateChartSlabNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||
|
||||
public InterestRateChartSlabNotFoundException(final Long id) {
|
||||
super("error.msg.interest.rate.chart.slab.id.invalid", "Interest rate chart slab with identifier " + id + " does not exist", id);
|
||||
}
|
||||
|
||||
public InterestRateChartSlabNotFoundException(final Long id, final Long chartId) {
|
||||
super("error.msg.interest.rate.chart.slab.id.invalid",
|
||||
"Interest rate chart slab with identifier " + id + " does not exist in interest chart with identifier " + chartId, id,
|
||||
chartId);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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.interestratechart.incentive;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import org.apache.fineract.portfolio.common.domain.ConditionType;
|
||||
|
||||
public abstract class AttributeIncentiveCalculation {
|
||||
|
||||
public abstract BigDecimal calculateIncentive(IncentiveDTO incentiveDTO);
|
||||
|
||||
public boolean applyIncentive(ConditionType conditionType, Long attributeValue, Long actualValue) {
|
||||
boolean applyIncentive = false;
|
||||
int compareVal = actualValue.compareTo(attributeValue);
|
||||
switch (conditionType) {
|
||||
case LESSTHAN:
|
||||
applyIncentive = compareVal < 0;
|
||||
break;
|
||||
case EQUAL:
|
||||
applyIncentive = compareVal == 0;
|
||||
break;
|
||||
case NOT_EQUAL:
|
||||
applyIncentive = compareVal != 0;
|
||||
break;
|
||||
case GRETERTHAN:
|
||||
applyIncentive = compareVal > 0;
|
||||
break;
|
||||
default:
|
||||
applyIncentive = false;
|
||||
break;
|
||||
}
|
||||
return applyIncentive;
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.interestratechart.incentive;
|
||||
|
||||
public final class AttributeIncentiveCalculationFactory {
|
||||
|
||||
private AttributeIncentiveCalculationFactory() {
|
||||
|
||||
}
|
||||
|
||||
public static AttributeIncentiveCalculation findAttributeIncentiveCalculation(InterestIncentiveEntityType entityType) {
|
||||
AttributeIncentiveCalculation attributeIncentiveCalculation = null;
|
||||
switch (entityType) {
|
||||
case CUSTOMER:
|
||||
attributeIncentiveCalculation = new ClientAttributeIncentiveCalculation();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return attributeIncentiveCalculation;
|
||||
}
|
||||
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* 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.interestratechart.incentive;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestIncentivesFields;
|
||||
|
||||
public class ClientAttributeIncentiveCalculation extends AttributeIncentiveCalculation {
|
||||
|
||||
@Override
|
||||
public BigDecimal calculateIncentive(IncentiveDTO incentiveDTO) {
|
||||
final Client client = incentiveDTO.client();
|
||||
BigDecimal interest = incentiveDTO.interest();
|
||||
final InterestIncentivesFields incentivesFields = incentiveDTO.incentives();
|
||||
boolean applyIncentive = false;
|
||||
switch (incentivesFields.attributeName()) {
|
||||
case GENDER:
|
||||
if (client.genderId() != null) {
|
||||
applyIncentive = applyIncentive(incentivesFields.conditionType(), Long.valueOf(incentivesFields.attributeValue()),
|
||||
client.genderId());
|
||||
}
|
||||
break;
|
||||
case AGE:
|
||||
if (client.dateOfBirth() != null) {
|
||||
final LocalDate dobLocalDate = client.dateOfBirth();
|
||||
final int age = Math.toIntExact(ChronoUnit.YEARS.between(dobLocalDate, DateUtils.getBusinessLocalDate()));
|
||||
applyIncentive = applyIncentive(incentivesFields.conditionType(), Long.valueOf(incentivesFields.attributeValue()),
|
||||
(long) age);
|
||||
}
|
||||
break;
|
||||
case CLIENT_TYPE:
|
||||
if (client.clientTypeId() != null) {
|
||||
applyIncentive = applyIncentive(incentivesFields.conditionType(), Long.valueOf(incentivesFields.attributeValue()),
|
||||
client.clientTypeId());
|
||||
}
|
||||
break;
|
||||
case CLIENT_CLASSIFICATION:
|
||||
if (client.clientClassificationId() != null) {
|
||||
applyIncentive = applyIncentive(incentivesFields.conditionType(), Long.valueOf(incentivesFields.attributeValue()),
|
||||
client.clientClassificationId());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
if (applyIncentive) {
|
||||
switch (incentivesFields.incentiveType()) {
|
||||
case FIXED:
|
||||
interest = incentivesFields.amount();
|
||||
break;
|
||||
case INCENTIVE:
|
||||
interest = interest.add(incentivesFields.amount());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return interest;
|
||||
}
|
||||
|
||||
}
|
||||
+48
@@ -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.interestratechart.incentive;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestIncentivesFields;
|
||||
|
||||
public class IncentiveDTO {
|
||||
|
||||
private final Client client;
|
||||
private final BigDecimal interest;
|
||||
private final InterestIncentivesFields incentives;
|
||||
|
||||
public IncentiveDTO(final Client client, final BigDecimal interest, final InterestIncentivesFields incentives) {
|
||||
this.client = client;
|
||||
this.interest = interest;
|
||||
this.incentives = incentives;
|
||||
}
|
||||
|
||||
public Client client() {
|
||||
return this.client;
|
||||
}
|
||||
|
||||
public BigDecimal interest() {
|
||||
return this.interest;
|
||||
}
|
||||
|
||||
public InterestIncentivesFields incentives() {
|
||||
return this.incentives;
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* 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.interestratechart.incentive;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public enum InterestIncentiveAttributeName {
|
||||
|
||||
INVALID(1, "InterestIncentiveAttributeName.invalid"), //
|
||||
GENDER(2, "InterestIncentiveAttributeName.gender"), //
|
||||
AGE(3, "InterestIncentiveAttributeName.age"), //
|
||||
CLIENT_TYPE(4, "InterestIncentiveAttributeName.clientType"), //
|
||||
CLIENT_CLASSIFICATION(5, "InterestIncentiveAttributeName.clientClassification"); //
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
public static InterestIncentiveAttributeName fromInt(final Integer value) {
|
||||
switch (value) {
|
||||
case 2:
|
||||
return GENDER;
|
||||
case 3:
|
||||
return AGE;
|
||||
case 4:
|
||||
return CLIENT_TYPE;
|
||||
case 5:
|
||||
return CLIENT_CLASSIFICATION;
|
||||
default:
|
||||
return INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
InterestIncentiveAttributeName(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toString().replaceAll("_", " ");
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
// TODO: why not just use the enum values... just more boilerplate code here!!
|
||||
public boolean isGender() {
|
||||
return GENDER.equals(this);
|
||||
}
|
||||
|
||||
// TODO: why not just use the enum values... just more boilerplate code here!!
|
||||
public boolean isAge() {
|
||||
return AGE.equals(this);
|
||||
}
|
||||
|
||||
// TODO: why not just use the enum values... just more boilerplate code here!!
|
||||
public boolean isClientType() {
|
||||
return CLIENT_TYPE.equals(this);
|
||||
}
|
||||
|
||||
// TODO: why not just use the enum values... just more boilerplate code here!!
|
||||
public boolean isClientClassification() {
|
||||
return CLIENT_CLASSIFICATION.equals(this);
|
||||
}
|
||||
|
||||
// TODO: why not just use the enum values... just more boilerplate code here!!
|
||||
public boolean isInvalid() {
|
||||
return INVALID.equals(this);
|
||||
}
|
||||
|
||||
// TODO: why not just use the enum values... just more boilerplate code here!!
|
||||
public static boolean isCodeValueAttribute(InterestIncentiveAttributeName attributeName) {
|
||||
switch (attributeName) {
|
||||
case GENDER:
|
||||
case CLIENT_TYPE:
|
||||
case CLIENT_CLASSIFICATION:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: do we really need this?!?
|
||||
public static Object[] integerValues() {
|
||||
return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray();
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* 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.interestratechart.incentive;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public enum InterestIncentiveEntityType {
|
||||
|
||||
INVALID(1, "InterestIncentiveEntityType.invalid"), //
|
||||
CUSTOMER(2, "InterestIncentiveEntityType.customer"), //
|
||||
ACCOUNT(3, "InterestIncentiveEntityType.account"); //
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
public static InterestIncentiveEntityType fromInt(final Integer v) {
|
||||
if (v == null) {
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
switch (v) {
|
||||
case 2:
|
||||
return CUSTOMER;
|
||||
case 3:
|
||||
return ACCOUNT;
|
||||
default:
|
||||
return INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
InterestIncentiveEntityType(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toString().replaceAll("_", " ");
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public boolean isCustomer() {
|
||||
return CUSTOMER.equals(this);
|
||||
}
|
||||
|
||||
public boolean isInvalid() {
|
||||
return INVALID.equals(this);
|
||||
}
|
||||
|
||||
// TODO: do we really need this?!?
|
||||
public static Object[] integerValues() {
|
||||
return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray();
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* 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.interestratechart.incentive;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public enum InterestIncentiveType {
|
||||
|
||||
INVALID(1, "InterestIncentiveType.invalid"), //
|
||||
FIXED(2, "InterestIncentiveType.fixed"), //
|
||||
INCENTIVE(3, "InterestIncentiveType.incentive"); //
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
public static InterestIncentiveType fromInt(final Integer v) {
|
||||
if (v == null) {
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
switch (v) {
|
||||
case 2:
|
||||
return FIXED;
|
||||
case 3:
|
||||
return INCENTIVE;
|
||||
default:
|
||||
return INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
InterestIncentiveType(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toString().replaceAll("_", " ");
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
// TODO: why not just use the enum values... just more boilerplate code here!!
|
||||
public boolean isIncentive() {
|
||||
return INCENTIVE.equals(this);
|
||||
}
|
||||
|
||||
// TODO: why not just use the enum values... just more boilerplate code here!!
|
||||
public boolean isFixed() {
|
||||
return FIXED.equals(this);
|
||||
}
|
||||
|
||||
// TODO: why not just use the enum values... just more boilerplate code here!!
|
||||
public boolean isInvalid() {
|
||||
return INVALID.equals(this);
|
||||
}
|
||||
|
||||
// TODO: do we really need this?!?
|
||||
public static Object[] integerValues() {
|
||||
return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray();
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.interestratechart.service;
|
||||
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.INCENTIVE_RESOURCE_NAME;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.amountParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.attributeNameParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.attributeValueParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.conditionTypeParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.entityTypeParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestIncentiveApiConstants.incentiveTypeparamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.incentivesParamName;
|
||||
|
||||
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.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestIncentives;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestIncentivesFields;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestRateChartSlab;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class InterestIncentiveAssembler {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
public Collection<InterestIncentives> assembleIncentivesFrom(final JsonElement element, InterestRateChartSlab interestRateChartSlab,
|
||||
final Locale locale) {
|
||||
final Collection<InterestIncentives> interestIncentivesSet = new HashSet<>();
|
||||
|
||||
if (element.isJsonObject()) {
|
||||
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
||||
if (topLevelJsonElement.has(incentivesParamName) && topLevelJsonElement.get(incentivesParamName).isJsonArray()) {
|
||||
final JsonArray array = topLevelJsonElement.get(incentivesParamName).getAsJsonArray();
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
final JsonObject incentiveElement = array.get(i).getAsJsonObject();
|
||||
final InterestIncentives incentives = this.assembleFrom(incentiveElement, interestRateChartSlab, locale);
|
||||
interestIncentivesSet.add(incentives);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return interestIncentivesSet;
|
||||
}
|
||||
|
||||
private InterestIncentives assembleFrom(final JsonElement element, final InterestRateChartSlab interestRateChartSlab,
|
||||
final Locale locale) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(INCENTIVE_RESOURCE_NAME);
|
||||
InterestIncentivesFields incentivesFields = createInterestIncentiveFields(element, baseDataValidator, locale);
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
return new InterestIncentives(interestRateChartSlab, incentivesFields);
|
||||
}
|
||||
|
||||
private InterestIncentivesFields createInterestIncentiveFields(final JsonElement element, final DataValidatorBuilder baseDataValidator,
|
||||
final Locale locale) {
|
||||
Integer entityType = this.fromApiJsonHelper.extractIntegerNamed(entityTypeParamName, element, locale);
|
||||
Integer conditionType = this.fromApiJsonHelper.extractIntegerNamed(conditionTypeParamName, element, locale);
|
||||
Integer attributeName = this.fromApiJsonHelper.extractIntegerNamed(attributeNameParamName, element, locale);
|
||||
String attributeValue = this.fromApiJsonHelper.extractStringNamed(attributeValueParamName, element);
|
||||
Integer incentiveType = this.fromApiJsonHelper.extractIntegerNamed(incentiveTypeparamName, element, locale);
|
||||
BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalNamed(amountParamName, element, locale);
|
||||
return InterestIncentivesFields.createNew(entityType, attributeName, conditionType, attributeValue, incentiveType, amount,
|
||||
baseDataValidator);
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* 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.interestratechart.service;
|
||||
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.INTERESTRATE_CHART_RESOURCE_NAME;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.descriptionParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.endDateParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.fromDateParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.isPrimaryGroupingByAmountParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.nameParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.currencyCodeParamName;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestRateChart;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestRateChartFields;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestRateChartRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestRateChartSlab;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class InterestRateChartAssembler {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final InterestRateChartRepositoryWrapper interestRateChartRepositoryWrapper;
|
||||
private final InterestRateChartSlabAssembler chartSlabAssembler;
|
||||
|
||||
/**
|
||||
* Assembles a new {@link InterestRateChart} from JSON Slabs passed in request
|
||||
*/
|
||||
public InterestRateChart assembleFrom(final JsonCommand command) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(INTERESTRATE_CHART_RESOURCE_NAME);
|
||||
final JsonElement element = command.parsedJson();
|
||||
final String currencyCode = this.fromApiJsonHelper.extractStringNamed(currencyCodeParamName, element);
|
||||
final InterestRateChart newChart = this.assembleFrom(element, currencyCode, baseDataValidator);
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
return newChart;
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
public InterestRateChart assembleFrom(final JsonElement element, final String currencyCode,
|
||||
final DataValidatorBuilder baseDataValidator) {
|
||||
|
||||
final String name = this.fromApiJsonHelper.extractStringNamed(nameParamName, element);
|
||||
final String description = this.fromApiJsonHelper.extractStringNamed(descriptionParamName, element);
|
||||
final LocalDate fromDate = this.fromApiJsonHelper.extractLocalDateNamed(fromDateParamName, element);
|
||||
final LocalDate toDate = this.fromApiJsonHelper.extractLocalDateNamed(endDateParamName, element);
|
||||
Boolean isPrimaryGroupingByAmount = this.fromApiJsonHelper.extractBooleanNamed(isPrimaryGroupingByAmountParamName, element);
|
||||
if (isPrimaryGroupingByAmount == null) {
|
||||
isPrimaryGroupingByAmount = false;
|
||||
}
|
||||
|
||||
// assemble chart Slabs
|
||||
final Collection<InterestRateChartSlab> newChartSlabs = this.chartSlabAssembler.assembleChartSlabsFrom(element, currencyCode);
|
||||
|
||||
final InterestRateChartFields fields = InterestRateChartFields.createNew(name, description, fromDate, toDate,
|
||||
isPrimaryGroupingByAmount);
|
||||
final InterestRateChart newChart = InterestRateChart.createNew(fields, newChartSlabs);
|
||||
newChart.validateChartSlabs(baseDataValidator);
|
||||
return newChart;
|
||||
}
|
||||
|
||||
public InterestRateChart assembleFrom(final Long interestRateChartId) {
|
||||
final InterestRateChart interestRateChart = this.interestRateChartRepositoryWrapper
|
||||
.findOneWithNotFoundDetection(interestRateChartId);
|
||||
return interestRateChart;
|
||||
}
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* 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.interestratechart.service;
|
||||
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.chartSlabs;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.descriptionParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.INTERESTRATE_CHART_SLAB_RESOURCE_NAME;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.amountRangeFromParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.amountRangeToParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.annualInterestRateParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.currencyCodeParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.fromPeriodParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.periodTypeParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.toPeriodParamName;
|
||||
|
||||
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.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestRateChart;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestRateChartRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestRateChartSlab;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestRateChartSlabFields;
|
||||
import org.apache.fineract.portfolio.interestratechart.exception.InterestRateChartSlabNotFoundException;
|
||||
import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class InterestRateChartSlabAssembler {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final InterestRateChartRepositoryWrapper interestRateChartRepositoryWrapper;
|
||||
private final InterestIncentiveAssembler incentiveAssembler;
|
||||
|
||||
/**
|
||||
* Assembles a new {@link InterestRateChartSlab} from JSON Slabs passed in request
|
||||
*/
|
||||
public InterestRateChartSlab assembleFrom(final JsonCommand command) {
|
||||
|
||||
final JsonElement element = command.parsedJson();
|
||||
final JsonObject elementObject = element.getAsJsonObject();
|
||||
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(elementObject);
|
||||
final String currencyCode = command.stringValueOfParameterNamed(currencyCodeParamName);
|
||||
|
||||
final Long chartId = command.subentityId();// returns chart id
|
||||
|
||||
final InterestRateChart chart = this.interestRateChartRepositoryWrapper.findOneWithNotFoundDetection(chartId);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(INTERESTRATE_CHART_SLAB_RESOURCE_NAME);
|
||||
|
||||
final InterestRateChartSlab newChartSlab = assembleChartSlabs(chart, elementObject, currencyCode, locale);
|
||||
// validate chart Slabs
|
||||
newChartSlab.slabFields().validateChartSlabPlatformRules(command, baseDataValidator, locale);
|
||||
chart.validateChartSlabs(baseDataValidator);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
return newChartSlab;
|
||||
}
|
||||
|
||||
private InterestRateChartSlab assembleChartSlabs(final InterestRateChart interestRateChart, final JsonElement element,
|
||||
final String currencyCode, final Locale locale) {
|
||||
final String description = this.fromApiJsonHelper.extractStringNamed(descriptionParamName, element);
|
||||
final Integer periodTypeId = this.fromApiJsonHelper.extractIntegerNamed(periodTypeParamName, element, locale);
|
||||
final SavingsPeriodFrequencyType periodType = SavingsPeriodFrequencyType.fromInt(periodTypeId);
|
||||
final Integer fromPeriod = this.fromApiJsonHelper.extractIntegerNamed(fromPeriodParamName, element, locale);
|
||||
final Integer toPeriod = this.fromApiJsonHelper.extractIntegerNamed(toPeriodParamName, element, locale);
|
||||
final BigDecimal amountRangeFrom = this.fromApiJsonHelper.extractBigDecimalNamed(amountRangeFromParamName, element, locale);
|
||||
final BigDecimal amountRangeTo = this.fromApiJsonHelper.extractBigDecimalNamed(amountRangeToParamName, element, locale);
|
||||
final BigDecimal annualInterestRate = this.fromApiJsonHelper.extractBigDecimalNamed(annualInterestRateParamName, element, locale);
|
||||
|
||||
final InterestRateChartSlabFields slabFields = InterestRateChartSlabFields.createNew(description, periodType, fromPeriod, toPeriod,
|
||||
amountRangeFrom, amountRangeTo, annualInterestRate, currencyCode);
|
||||
InterestRateChartSlab interestRateChartSlab = InterestRateChartSlab.createNew(slabFields, interestRateChart);
|
||||
this.incentiveAssembler.assembleIncentivesFrom(element, interestRateChartSlab, locale);
|
||||
return interestRateChartSlab;
|
||||
|
||||
}
|
||||
|
||||
public InterestRateChartSlab assembleFrom(final Long chartSlabId, final Long chartId) {
|
||||
final InterestRateChart chart = this.interestRateChartRepositoryWrapper.findOneWithNotFoundDetection(chartId);
|
||||
final InterestRateChartSlab interestRateChartSlab = chart.findChartSlab(chartSlabId);
|
||||
|
||||
if (interestRateChartSlab == null) {
|
||||
throw new InterestRateChartSlabNotFoundException(chartSlabId, chartId);
|
||||
}
|
||||
|
||||
return interestRateChartSlab;
|
||||
}
|
||||
|
||||
public Collection<InterestRateChartSlab> assembleChartSlabsFrom(final JsonElement element, String currencyCode) {
|
||||
final Collection<InterestRateChartSlab> interestRateChartSlabsSet = new HashSet<>();
|
||||
|
||||
if (element.isJsonObject()) {
|
||||
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
||||
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
|
||||
if (topLevelJsonElement.has(chartSlabs) && topLevelJsonElement.get(chartSlabs).isJsonArray()) {
|
||||
final JsonArray array = topLevelJsonElement.get(chartSlabs).getAsJsonArray();
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
final JsonObject interstRateChartElement = array.get(i).getAsJsonObject();
|
||||
final InterestRateChartSlab chartSlab = this.assembleChartSlabs(null, interstRateChartElement, currencyCode, locale);
|
||||
interestRateChartSlabsSet.add(chartSlab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return interestRateChartSlabsSet;
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarFrequencyType;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public final class DepositAccountUtils {
|
||||
|
||||
private DepositAccountUtils() {
|
||||
|
||||
}
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DepositAccountUtils.class);
|
||||
|
||||
public static final int GENERATE_MINIMUM_NUMBER_OF_FUTURE_INSTALMENTS = 5;
|
||||
|
||||
public static LocalDate calculateNextDepositDate(final LocalDate lastDepositDate, final PeriodFrequencyType frequency,
|
||||
final int recurringEvery) {
|
||||
LocalDate nextDepositDate = lastDepositDate;
|
||||
|
||||
switch (frequency) {
|
||||
case DAYS:
|
||||
nextDepositDate = lastDepositDate.plusDays(recurringEvery);
|
||||
break;
|
||||
case WEEKS:
|
||||
nextDepositDate = lastDepositDate.plusWeeks(recurringEvery);
|
||||
break;
|
||||
case MONTHS:
|
||||
nextDepositDate = lastDepositDate.plusMonths(recurringEvery);
|
||||
break;
|
||||
case YEARS:
|
||||
nextDepositDate = lastDepositDate.plusYears(recurringEvery);
|
||||
break;
|
||||
case INVALID:
|
||||
break;
|
||||
case WHOLE_TERM:
|
||||
LOG.error("TODO Implement calculateNextDepositDate for WHOLE_TERM");
|
||||
break;
|
||||
}
|
||||
return nextDepositDate;
|
||||
}
|
||||
|
||||
public static LocalDate calculateNextDepositDate(final LocalDate lastDepositDate, final String recurrence) {
|
||||
final PeriodFrequencyType frequencyType = CalendarFrequencyType.from(CalendarUtils.getFrequency(recurrence));
|
||||
Integer frequency = CalendarUtils.getInterval(recurrence);
|
||||
frequency = frequency == -1 ? 1 : frequency;
|
||||
return calculateNextDepositDate(lastDepositDate, frequencyType, frequency);
|
||||
}
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings;
|
||||
|
||||
public class SavingsTransactionBooleanValues {
|
||||
|
||||
private final boolean isAccountTransfer;
|
||||
private final boolean isRegularTransaction;
|
||||
private final boolean isApplyWithdrawFee;
|
||||
private final boolean isInterestTransfer;
|
||||
private final boolean isExceptionForBalanceCheck;
|
||||
|
||||
public SavingsTransactionBooleanValues(final boolean isAccountTransfer, final boolean isRegularTransaction,
|
||||
final boolean isApplyWithdrawFee, final boolean isInterestTransfer, final boolean isExceptionForBalanceCheck) {
|
||||
|
||||
this.isAccountTransfer = isAccountTransfer;
|
||||
this.isRegularTransaction = isRegularTransaction;
|
||||
this.isApplyWithdrawFee = isApplyWithdrawFee;
|
||||
this.isInterestTransfer = isInterestTransfer;
|
||||
this.isExceptionForBalanceCheck = isExceptionForBalanceCheck;
|
||||
}
|
||||
|
||||
public boolean isAccountTransfer() {
|
||||
return this.isAccountTransfer;
|
||||
}
|
||||
|
||||
public boolean isRegularTransaction() {
|
||||
return this.isRegularTransaction;
|
||||
}
|
||||
|
||||
public boolean isApplyWithdrawFee() {
|
||||
return this.isApplyWithdrawFee;
|
||||
}
|
||||
|
||||
public boolean isInterestTransfer() {
|
||||
return this.isInterestTransfer;
|
||||
}
|
||||
|
||||
public boolean isExceptionForBalanceCheck() {
|
||||
return this.isExceptionForBalanceCheck;
|
||||
}
|
||||
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* 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.api;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
|
||||
import org.apache.fineract.portfolio.savings.data.SavingsAccountData;
|
||||
import org.apache.fineract.portfolio.savings.data.SavingsProductData;
|
||||
|
||||
public class SavingsApiSetConstants extends SavingsApiConstants {
|
||||
|
||||
/**
|
||||
* These parameters will match the class level parameters of {@link SavingsProductData}. Where possible, we try to
|
||||
* get response parameters to match those of request parameters.
|
||||
*/
|
||||
protected static final Set<String> SAVINGS_PRODUCT_RESPONSE_DATA_PARAMETERS = new HashSet<>(
|
||||
Arrays.asList(idParamName, nameParamName, shortNameParamName, descriptionParamName, "currency", digitsAfterDecimalParamName,
|
||||
inMultiplesOfParamName, nominalAnnualInterestRateParamName, interestCompoundingPeriodTypeParamName,
|
||||
interestPostingPeriodTypeParamName, interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName,
|
||||
minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName,
|
||||
withdrawalFeeAmountParamName, withdrawalFeeTypeParamName, withdrawalFeeForTransfersParamName, feeAmountParamName,
|
||||
feeOnMonthDayParamName, "currencyOptions", "interestCompoundingPeriodTypeOptions", "interestPostingPeriodTypeOptions",
|
||||
"interestCalculationTypeOptions", "interestCalculationDaysInYearTypeOptions", "lockinPeriodFrequencyTypeOptions",
|
||||
"withdrawalFeeTypeOptions", nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName,
|
||||
withHoldTaxParamName, taxGroupIdParamName, isDormancyTrackingActiveParamName, daysToInactiveParamName,
|
||||
daysToDormancyParamName, daysToInactiveParamName, accountMappingForPaymentParamName));
|
||||
|
||||
/**
|
||||
* These parameters will match the class level parameters of {@link SavingsAccountData}. Where possible, we try to
|
||||
* get response parameters to match those of request parameters.
|
||||
*/
|
||||
protected static final Set<String> SAVINGS_ACCOUNT_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName,
|
||||
accountNoParamName, externalIdParamName, statusParamName, activatedOnDateParamName, staffIdParamName, clientIdParamName,
|
||||
"clientName", groupIdParamName, "groupName", "savingsProductId", "savingsProductName", "currency",
|
||||
nominalAnnualInterestRateParamName, interestCompoundingPeriodTypeParamName, interestCalculationTypeParamName,
|
||||
interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName,
|
||||
lockinPeriodFrequencyTypeParamName, withdrawalFeeAmountParamName, withdrawalFeeTypeParamName,
|
||||
withdrawalFeeForTransfersParamName, feeAmountParamName, feeOnMonthDayParamName, "summary", "transactions", "productOptions",
|
||||
"interestCompoundingPeriodTypeOptions", "interestPostingPeriodTypeOptions", "interestCalculationTypeOptions",
|
||||
"interestCalculationDaysInYearTypeOptions", "lockinPeriodFrequencyTypeOptions", "withdrawalFeeTypeOptions", "withdrawalFee",
|
||||
"annualFee", onHoldFundsParamName, nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName,
|
||||
datatables, savingsAmountOnHold, accountMappingForPaymentParamName, interestPostedTillDate));
|
||||
|
||||
protected static final Set<String> SAVINGS_TRANSACTION_RESPONSE_DATA_PARAMETERS = new HashSet<>(
|
||||
Arrays.asList(idParamName, "accountId", accountNoParamName, "currency", "amount", dateParamName, paymentDetailDataParamName,
|
||||
runningBalanceParamName, reversedParamName, noteParamName));
|
||||
|
||||
protected static final Set<String> SAVINGS_ACCOUNT_CHARGES_RESPONSE_DATA_PARAMETERS = new HashSet<>(
|
||||
Arrays.asList(chargeIdParamName, savingsAccountChargeIdParamName, chargeNameParamName, penaltyParamName,
|
||||
chargeTimeTypeParamName, dueAsOfDateParamName, chargeCalculationTypeParamName, percentageParamName,
|
||||
amountPercentageAppliedToParamName, currencyParamName, amountWaivedParamName, amountWrittenOffParamName,
|
||||
amountOutstandingParamName, amountOrPercentageParamName, amountParamName, amountPaidParamName, chargeOptionsParamName));
|
||||
|
||||
protected static final Set<String> SAVINGS_ACCOUNT_ON_HOLD_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName,
|
||||
amountParamName, onHoldTransactionTypeParamName, onHoldTransactionDateParamName, onHoldReversedParamName));
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* 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.time.LocalDate;
|
||||
|
||||
public final class ClosingOfSavingsAccounts {
|
||||
|
||||
private final transient Integer rowIndex;
|
||||
|
||||
private final transient Long accountId;
|
||||
|
||||
private final LocalDate closedOnDate;
|
||||
|
||||
private final Long onAccountClosureId;
|
||||
|
||||
private final Long toSavingsAccountId;
|
||||
|
||||
private final String dateFormat;
|
||||
|
||||
private final String accountType;
|
||||
|
||||
private final String locale;
|
||||
|
||||
private final String note;
|
||||
|
||||
public static ClosingOfSavingsAccounts importInstance(Long accountId, LocalDate closedOnDate, Long onAccountClosureId,
|
||||
Long toSavingsAccountId, String accountType, Integer rowIndex, String locale, String dateFormat) {
|
||||
return new ClosingOfSavingsAccounts(accountId, closedOnDate, onAccountClosureId, toSavingsAccountId, accountType, rowIndex, locale,
|
||||
dateFormat);
|
||||
}
|
||||
|
||||
private ClosingOfSavingsAccounts(Long accountId, LocalDate closedOnDate, Long onAccountClosureId, Long toSavingsAccountId,
|
||||
String accountType, Integer rowIndex, String locale, String dateFormat) {
|
||||
this.accountId = accountId;
|
||||
this.closedOnDate = closedOnDate;
|
||||
this.onAccountClosureId = onAccountClosureId;
|
||||
this.toSavingsAccountId = toSavingsAccountId;
|
||||
this.accountType = accountType;
|
||||
this.rowIndex = rowIndex;
|
||||
this.dateFormat = dateFormat;
|
||||
this.locale = locale;
|
||||
this.note = "";
|
||||
}
|
||||
|
||||
public Integer getRowIndex() {
|
||||
return rowIndex;
|
||||
}
|
||||
|
||||
public Long getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public LocalDate getClosedOnDate() {
|
||||
return closedOnDate;
|
||||
}
|
||||
|
||||
public Long getOnAccountClosureId() {
|
||||
return onAccountClosureId;
|
||||
}
|
||||
|
||||
public Long getToSavingsAccountId() {
|
||||
return toSavingsAccountId;
|
||||
}
|
||||
|
||||
public String getDateFormat() {
|
||||
return dateFormat;
|
||||
}
|
||||
|
||||
public String getAccountType() {
|
||||
return accountType;
|
||||
}
|
||||
|
||||
public String getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
public String getNote() {
|
||||
return note;
|
||||
}
|
||||
}
|
||||
+338
@@ -0,0 +1,338 @@
|
||||
/**
|
||||
* 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.Collection;
|
||||
import java.util.HashSet;
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.organisation.staff.data.StaffData;
|
||||
import org.apache.fineract.portfolio.charge.data.ChargeData;
|
||||
import org.apache.fineract.portfolio.tax.data.TaxGroupData;
|
||||
|
||||
/**
|
||||
* Immutable data object representing abstract for Fixed and Recurring Deposit Accounts Accounts.
|
||||
*/
|
||||
@Getter
|
||||
public class DepositAccountData {
|
||||
|
||||
protected final Long id;
|
||||
protected final String accountNo;
|
||||
protected final String externalId;
|
||||
protected final Long groupId;
|
||||
protected final String groupName;
|
||||
protected final Long clientId;
|
||||
protected final String clientName;
|
||||
protected final Long depositProductId;
|
||||
protected final String depositProductName;
|
||||
protected final Long fieldOfficerId;
|
||||
protected final String fieldOfficerName;
|
||||
protected final SavingsAccountStatusEnumData status;
|
||||
protected final SavingsAccountApplicationTimelineData timeline;
|
||||
protected final CurrencyData currency;
|
||||
protected final BigDecimal nominalAnnualInterestRate;
|
||||
protected final EnumOptionData interestCompoundingPeriodType;
|
||||
protected final EnumOptionData interestPostingPeriodType;
|
||||
protected final EnumOptionData interestCalculationType;
|
||||
protected final EnumOptionData interestCalculationDaysInYearType;
|
||||
protected final BigDecimal minRequiredOpeningBalance;
|
||||
protected final Integer lockinPeriodFrequency;
|
||||
protected final EnumOptionData lockinPeriodFrequencyType;
|
||||
protected final boolean withdrawalFeeForTransfers;
|
||||
protected final EnumOptionData depositType;
|
||||
protected final BigDecimal minBalanceForInterestCalculation;
|
||||
protected final boolean withHoldTax;
|
||||
protected final TaxGroupData taxGroup;
|
||||
|
||||
// associations
|
||||
protected final SavingsAccountSummaryData summary;
|
||||
protected final Collection<SavingsAccountTransactionData> transactions;
|
||||
|
||||
protected final Collection<SavingsAccountChargeData> charges;
|
||||
protected final DepositAccountInterestRateChartData accountChart;
|
||||
|
||||
// template
|
||||
protected final Collection<DepositProductData> productOptions;
|
||||
protected final Collection<StaffData> fieldOfficerOptions;
|
||||
protected final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions;
|
||||
protected final Collection<EnumOptionData> interestPostingPeriodTypeOptions;
|
||||
protected final Collection<EnumOptionData> interestCalculationTypeOptions;
|
||||
protected final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions;
|
||||
protected final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions;
|
||||
protected final Collection<EnumOptionData> withdrawalFeeTypeOptions;
|
||||
protected final Collection<ChargeData> chargeOptions;
|
||||
|
||||
protected final SavingsAccountChargeData withdrawalFee;
|
||||
protected final SavingsAccountChargeData annualFee;
|
||||
|
||||
protected final DepositAccountInterestRateChartData chartTemplate;
|
||||
|
||||
// import fields
|
||||
private Long productId;
|
||||
|
||||
public DepositAccountData(Long clientId, Long productId, Long fieldOfficerId, EnumOptionData interestCompoundingPeriodType,
|
||||
EnumOptionData interestPostingPeriodType, EnumOptionData interestCalculationType,
|
||||
EnumOptionData interestCalculationDaysInYearType, Integer lockinPeriodFrequency, EnumOptionData lockinPeriodFrequencyType,
|
||||
String externalId, Collection<SavingsAccountChargeData> charges) {
|
||||
this.id = null;
|
||||
this.accountNo = null;
|
||||
this.externalId = externalId;
|
||||
this.groupId = null;
|
||||
this.groupName = null;
|
||||
this.clientId = clientId;
|
||||
this.clientName = null;
|
||||
this.depositProductId = null;
|
||||
this.depositProductName = null;
|
||||
this.fieldOfficerId = fieldOfficerId;
|
||||
this.fieldOfficerName = null;
|
||||
this.status = null;
|
||||
this.timeline = null;
|
||||
this.currency = null;
|
||||
this.nominalAnnualInterestRate = null;
|
||||
this.interestCompoundingPeriodType = interestCompoundingPeriodType;
|
||||
this.interestPostingPeriodType = interestPostingPeriodType;
|
||||
this.interestCalculationType = interestCalculationType;
|
||||
this.interestCalculationDaysInYearType = interestCalculationDaysInYearType;
|
||||
this.minRequiredOpeningBalance = null;
|
||||
this.lockinPeriodFrequency = lockinPeriodFrequency;
|
||||
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType;
|
||||
this.withdrawalFeeForTransfers = false;
|
||||
this.depositType = null;
|
||||
this.minBalanceForInterestCalculation = null;
|
||||
this.withHoldTax = false;
|
||||
this.taxGroup = null;
|
||||
this.summary = null;
|
||||
this.transactions = null;
|
||||
this.charges = charges;
|
||||
this.accountChart = null;
|
||||
this.productOptions = null;
|
||||
this.fieldOfficerOptions = null;
|
||||
this.interestCompoundingPeriodTypeOptions = null;
|
||||
this.interestPostingPeriodTypeOptions = null;
|
||||
this.interestCalculationTypeOptions = null;
|
||||
this.interestCalculationDaysInYearTypeOptions = null;
|
||||
this.lockinPeriodFrequencyTypeOptions = null;
|
||||
this.withdrawalFeeTypeOptions = null;
|
||||
this.chargeOptions = null;
|
||||
this.withdrawalFee = null;
|
||||
this.annualFee = null;
|
||||
this.chartTemplate = null;
|
||||
this.productId = productId;
|
||||
}
|
||||
|
||||
public static DepositAccountData instance(final Long id, final String accountNo, final String externalId, final Long groupId,
|
||||
final String groupName, final Long clientId, final String clientName, final Long productId, final String productName,
|
||||
final Long fieldOfficerId, final String fieldOfficerName, final SavingsAccountStatusEnumData status,
|
||||
final SavingsAccountApplicationTimelineData timeline, final CurrencyData currency, final BigDecimal interestRate,
|
||||
final EnumOptionData interestCompoundingPeriodType, final EnumOptionData interestPostingPeriodType,
|
||||
final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType,
|
||||
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType,
|
||||
final boolean withdrawalFeeForTransfers, final SavingsAccountSummaryData summary, final EnumOptionData depositType,
|
||||
final BigDecimal minBalanceForInterestCalculation, final boolean withHoldTax, final TaxGroupData taxGroup) {
|
||||
|
||||
final Collection<DepositProductData> productOptions = null;
|
||||
final Collection<StaffData> fieldOfficerOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
|
||||
final Collection<SavingsAccountTransactionData> transactions = null;
|
||||
final Collection<SavingsAccountChargeData> charges = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final DepositAccountInterestRateChartData accountChart = null;
|
||||
final DepositAccountInterestRateChartData chartTemplate = null;
|
||||
|
||||
return new DepositAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
|
||||
fieldOfficerId, fieldOfficerName, status, timeline, currency, interestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary, transactions, productOptions,
|
||||
fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, charges,
|
||||
chargeOptions, accountChart, chartTemplate, depositType, minBalanceForInterestCalculation, withHoldTax, taxGroup);
|
||||
}
|
||||
|
||||
public static DepositAccountData lookup(final Long id, final String accountNo, final EnumOptionData depositType) {
|
||||
|
||||
final String externalId = null;
|
||||
final Long groupId = null;
|
||||
final String groupName = null;
|
||||
final Long clientId = null;
|
||||
final String clientName = null;
|
||||
final Long productId = null;
|
||||
final String productName = null;
|
||||
final Long fieldOfficerId = null;
|
||||
final String fieldOfficerName = null;
|
||||
final SavingsAccountStatusEnumData status = null;
|
||||
final SavingsAccountApplicationTimelineData timeline = null;
|
||||
final CurrencyData currency = null;
|
||||
final BigDecimal interestRate = null;
|
||||
final EnumOptionData interestCompoundingPeriodType = null;
|
||||
final EnumOptionData interestPostingPeriodType = null;
|
||||
final EnumOptionData interestCalculationType = null;
|
||||
final EnumOptionData interestCalculationDaysInYearType = null;
|
||||
final BigDecimal minRequiredOpeningBalance = null;
|
||||
final Integer lockinPeriodFrequency = null;
|
||||
final EnumOptionData lockinPeriodFrequencyType = null;
|
||||
final boolean withdrawalFeeForTransfers = false;
|
||||
final SavingsAccountSummaryData summary = null;
|
||||
final Collection<DepositProductData> productOptions = null;
|
||||
final Collection<StaffData> fieldOfficerOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
|
||||
final Collection<SavingsAccountTransactionData> transactions = null;
|
||||
final Collection<SavingsAccountChargeData> charges = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final DepositAccountInterestRateChartData accountChart = null;
|
||||
final DepositAccountInterestRateChartData chartTemplate = null;
|
||||
final BigDecimal minBalanceForInterestCalculation = null;
|
||||
final boolean withHoldTax = false;
|
||||
final TaxGroupData taxGroup = null;
|
||||
|
||||
return new DepositAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
|
||||
fieldOfficerId, fieldOfficerName, status, timeline, currency, interestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary, transactions, productOptions,
|
||||
fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, charges,
|
||||
chargeOptions, accountChart, chartTemplate, depositType, minBalanceForInterestCalculation, withHoldTax, taxGroup);
|
||||
}
|
||||
|
||||
protected DepositAccountData(final Long id, final String accountNo, final String externalId, final Long groupId, final String groupName,
|
||||
final Long clientId, final String clientName, final Long productId, final String productName, final Long fieldOfficerId,
|
||||
final String fieldOfficerName, final SavingsAccountStatusEnumData status, final SavingsAccountApplicationTimelineData timeline,
|
||||
final CurrencyData currency, final BigDecimal nominalAnnualInterestRate, final EnumOptionData interestPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final boolean withdrawalFeeForTransfers,
|
||||
final SavingsAccountSummaryData summary, final Collection<SavingsAccountTransactionData> transactions,
|
||||
final Collection<DepositProductData> productOptions, final Collection<StaffData> fieldOfficerOptions,
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<SavingsAccountChargeData> charges, final Collection<ChargeData> chargeOptions,
|
||||
final DepositAccountInterestRateChartData accountChart, final DepositAccountInterestRateChartData chartTemplate,
|
||||
final EnumOptionData depositType, final BigDecimal minBalanceForInterestCalculation, final boolean withHoldTax,
|
||||
final TaxGroupData taxGroup) {
|
||||
this.id = id;
|
||||
this.accountNo = accountNo;
|
||||
this.externalId = externalId;
|
||||
this.groupId = groupId;
|
||||
this.groupName = groupName;
|
||||
this.clientId = clientId;
|
||||
this.clientName = clientName;
|
||||
this.depositProductId = productId;
|
||||
this.depositProductName = productName;
|
||||
this.fieldOfficerId = fieldOfficerId;
|
||||
this.fieldOfficerName = fieldOfficerName;
|
||||
this.status = status;
|
||||
this.timeline = timeline;
|
||||
this.currency = currency;
|
||||
this.nominalAnnualInterestRate = nominalAnnualInterestRate;
|
||||
this.interestCompoundingPeriodType = interestPeriodType;
|
||||
this.interestPostingPeriodType = interestPostingPeriodType;
|
||||
this.interestCalculationType = interestCalculationType;
|
||||
this.interestCalculationDaysInYearType = interestCalculationDaysInYearType;
|
||||
this.minRequiredOpeningBalance = minRequiredOpeningBalance;
|
||||
this.lockinPeriodFrequency = lockinPeriodFrequency;
|
||||
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType;
|
||||
this.withdrawalFeeForTransfers = withdrawalFeeForTransfers;
|
||||
this.summary = summary;
|
||||
this.transactions = transactions;
|
||||
this.productOptions = productOptions;
|
||||
this.fieldOfficerOptions = fieldOfficerOptions;
|
||||
this.interestCompoundingPeriodTypeOptions = interestCompoundingPeriodTypeOptions;
|
||||
this.interestPostingPeriodTypeOptions = interestPostingPeriodTypeOptions;
|
||||
this.interestCalculationTypeOptions = interestCalculationTypeOptions;
|
||||
this.interestCalculationDaysInYearTypeOptions = interestCalculationDaysInYearTypeOptions;
|
||||
this.lockinPeriodFrequencyTypeOptions = lockinPeriodFrequencyTypeOptions;
|
||||
this.withdrawalFeeTypeOptions = withdrawalFeeTypeOptions;
|
||||
|
||||
this.charges = charges;// charges associated with Savings account
|
||||
// charges available for adding to Savings account
|
||||
this.chargeOptions = chargeOptions;
|
||||
|
||||
this.withdrawalFee = getWithdrawalFee();
|
||||
|
||||
this.annualFee = getAnnualFee();
|
||||
|
||||
this.accountChart = accountChart;
|
||||
this.chartTemplate = chartTemplate;
|
||||
this.depositType = depositType;
|
||||
this.minBalanceForInterestCalculation = minBalanceForInterestCalculation;
|
||||
this.taxGroup = taxGroup;
|
||||
this.withHoldTax = withHoldTax;
|
||||
}
|
||||
|
||||
private SavingsAccountChargeData getWithdrawalFee() {
|
||||
for (SavingsAccountChargeData charge : this.charges()) {
|
||||
if (charge.isWithdrawalFee()) {
|
||||
return charge;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private SavingsAccountChargeData getAnnualFee() {
|
||||
for (SavingsAccountChargeData charge : this.charges()) {
|
||||
if (charge.isAnnualFee()) {
|
||||
return charge;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof DepositAccountData)) {
|
||||
return false;
|
||||
}
|
||||
final DepositAccountData rhs = (DepositAccountData) obj;
|
||||
return new EqualsBuilder().append(this.id, rhs.id).append(this.accountNo, rhs.accountNo).isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37).append(this.id).append(this.accountNo).toHashCode();
|
||||
}
|
||||
|
||||
public Collection<SavingsAccountChargeData> charges() {
|
||||
return (this.charges == null) ? new HashSet<SavingsAccountChargeData>() : this.charges;
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* 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 org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.portfolio.interestratechart.data.InterestIncentiveData;
|
||||
|
||||
public final class DepositAccountInterestIncentiveData {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Long id;
|
||||
@SuppressWarnings("unused")
|
||||
private final EnumOptionData entityType;
|
||||
@SuppressWarnings("unused")
|
||||
private final EnumOptionData attributeName;
|
||||
@SuppressWarnings("unused")
|
||||
private final EnumOptionData conditionType;
|
||||
@SuppressWarnings("unused")
|
||||
private final String attributeValue;
|
||||
@SuppressWarnings("unused")
|
||||
private final String attributeValueDesc;
|
||||
@SuppressWarnings("unused")
|
||||
private final EnumOptionData incentiveType;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal amount;
|
||||
|
||||
public static DepositAccountInterestIncentiveData instance(final Long id, final EnumOptionData entityType,
|
||||
final EnumOptionData attributeName, final EnumOptionData conditionType, final String attributeValue,
|
||||
final String attributeValueDesc, final EnumOptionData incentiveType, final BigDecimal amount) {
|
||||
|
||||
return new DepositAccountInterestIncentiveData(id, entityType, attributeName, conditionType, attributeValue, attributeValueDesc,
|
||||
incentiveType, amount);
|
||||
}
|
||||
|
||||
public static DepositAccountInterestIncentiveData from(final InterestIncentiveData incentiveData) {
|
||||
final Long id = null;
|
||||
return new DepositAccountInterestIncentiveData(id, incentiveData.entityType(), incentiveData.attributeName(),
|
||||
incentiveData.conditionType(), incentiveData.attributeValue(), incentiveData.attributeValueDesc(),
|
||||
incentiveData.incentiveType(), incentiveData.amount());
|
||||
}
|
||||
|
||||
private DepositAccountInterestIncentiveData(final Long id, final EnumOptionData entityType, final EnumOptionData attributeName,
|
||||
final EnumOptionData conditionType, final String attributeValue, final String attributeValueDesc,
|
||||
final EnumOptionData incentiveType, final BigDecimal amount) {
|
||||
|
||||
this.id = id;
|
||||
this.entityType = entityType;
|
||||
this.attributeName = attributeName;
|
||||
this.conditionType = conditionType;
|
||||
this.attributeValue = attributeValue;
|
||||
this.attributeValueDesc = attributeValueDesc;
|
||||
this.incentiveType = incentiveType;
|
||||
this.amount = amount;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* 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.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.portfolio.interestratechart.data.InterestRateChartData;
|
||||
import org.apache.fineract.portfolio.interestratechart.data.InterestRateChartSlabData;
|
||||
|
||||
/**
|
||||
* Immutable data object representing a deposit account interest rate chart.
|
||||
*/
|
||||
public final class DepositAccountInterestRateChartData {
|
||||
|
||||
private final Long id;
|
||||
private final String name;
|
||||
private final String description;
|
||||
private final LocalDate fromDate;
|
||||
private final LocalDate endDate;
|
||||
private final boolean isPrimaryGroupingByAmount;
|
||||
private final Long accountId;
|
||||
private final String accountNumber;
|
||||
// associations
|
||||
private Collection<DepositAccountInterestRateChartSlabData> chartSlabs;
|
||||
|
||||
// template
|
||||
private final Collection<EnumOptionData> periodTypes;
|
||||
private final Collection<EnumOptionData> entityTypeOptions;
|
||||
private final Collection<EnumOptionData> attributeNameOptions;
|
||||
private final Collection<EnumOptionData> conditionTypeOptions;
|
||||
private final Collection<EnumOptionData> incentiveTypeOptions;
|
||||
private final Collection<CodeValueData> genderOptions;
|
||||
private final Collection<CodeValueData> clientTypeOptions;
|
||||
private final Collection<CodeValueData> clientClassificationOptions;
|
||||
|
||||
public static DepositAccountInterestRateChartData instance(Long id, String name, String description, LocalDate fromDate,
|
||||
LocalDate endDate, boolean isPrimaryGroupingByAmount, Long accountId, String accountNumber,
|
||||
Collection<DepositAccountInterestRateChartSlabData> chartSlabs, Collection<EnumOptionData> periodTypes) {
|
||||
|
||||
final Collection<EnumOptionData> entityTypeOptions = null;
|
||||
final Collection<EnumOptionData> attributeNameOptions = null;
|
||||
final Collection<EnumOptionData> conditionTypeOptions = null;
|
||||
final Collection<EnumOptionData> incentiveTypeOptions = null;
|
||||
final Collection<CodeValueData> genderOptions = null;
|
||||
final Collection<CodeValueData> clientTypeOptions = null;
|
||||
final Collection<CodeValueData> clientClassificationOptions = null;
|
||||
return new DepositAccountInterestRateChartData(id, name, description, fromDate, endDate, isPrimaryGroupingByAmount, accountId,
|
||||
accountNumber, chartSlabs, periodTypes, entityTypeOptions, attributeNameOptions, conditionTypeOptions, incentiveTypeOptions,
|
||||
genderOptions, clientTypeOptions, clientClassificationOptions);
|
||||
}
|
||||
|
||||
public static DepositAccountInterestRateChartData from(InterestRateChartData productChartData) {
|
||||
final Long id = null;
|
||||
final Long accountId = null;
|
||||
final String accountNumber = null;
|
||||
Collection<DepositAccountInterestRateChartSlabData> fromProdChartSlabs = new ArrayList<>();
|
||||
Collection<InterestRateChartSlabData> productChartSlabDatas = productChartData.chartSlabs();
|
||||
if (productChartSlabDatas != null) {
|
||||
for (InterestRateChartSlabData productChartSlabData : productChartSlabDatas) {
|
||||
fromProdChartSlabs.add(DepositAccountInterestRateChartSlabData.from(productChartSlabData));
|
||||
}
|
||||
}
|
||||
|
||||
return new DepositAccountInterestRateChartData(id, productChartData.name(), productChartData.description(),
|
||||
productChartData.fromDate(), productChartData.endDate(), productChartData.isPrimaryGroupingByAmount(), accountId,
|
||||
accountNumber, fromProdChartSlabs, productChartData.periodTypes(), productChartData.entityTypeOptions(),
|
||||
productChartData.attributeNameOptions(), productChartData.conditionTypeOptions(), productChartData.incentiveTypeOptions(),
|
||||
productChartData.genderOptions(), productChartData.clientTypeOptions(), productChartData.clientClassificationOptions());
|
||||
}
|
||||
|
||||
public static DepositAccountInterestRateChartData withSlabs(DepositAccountInterestRateChartData interestRateChartData,
|
||||
Collection<DepositAccountInterestRateChartSlabData> chartSlabs) {
|
||||
return new DepositAccountInterestRateChartData(interestRateChartData.id, interestRateChartData.name,
|
||||
interestRateChartData.description, interestRateChartData.fromDate, interestRateChartData.endDate,
|
||||
interestRateChartData.isPrimaryGroupingByAmount, interestRateChartData.accountId, interestRateChartData.accountNumber,
|
||||
chartSlabs, interestRateChartData.periodTypes, interestRateChartData.entityTypeOptions,
|
||||
interestRateChartData.attributeNameOptions, interestRateChartData.conditionTypeOptions,
|
||||
interestRateChartData.incentiveTypeOptions, interestRateChartData.genderOptions, interestRateChartData.clientTypeOptions,
|
||||
interestRateChartData.clientClassificationOptions);
|
||||
}
|
||||
|
||||
public static DepositAccountInterestRateChartData withTemplate(DepositAccountInterestRateChartData interestRateChartData,
|
||||
Collection<EnumOptionData> periodTypes, final Collection<EnumOptionData> entityTypeOptions,
|
||||
final Collection<EnumOptionData> attributeNameOptions, final Collection<EnumOptionData> conditionTypeOptions,
|
||||
final Collection<EnumOptionData> incentiveTypeOptions, final Collection<CodeValueData> genderOptions,
|
||||
final Collection<CodeValueData> clientTypeOptions, final Collection<CodeValueData> clientClassificationOptions) {
|
||||
return new DepositAccountInterestRateChartData(interestRateChartData.id, interestRateChartData.name,
|
||||
interestRateChartData.description, interestRateChartData.fromDate, interestRateChartData.endDate,
|
||||
interestRateChartData.isPrimaryGroupingByAmount, interestRateChartData.accountId, interestRateChartData.accountNumber,
|
||||
interestRateChartData.chartSlabs, periodTypes, entityTypeOptions, attributeNameOptions, conditionTypeOptions,
|
||||
incentiveTypeOptions, genderOptions, clientTypeOptions, clientClassificationOptions);
|
||||
}
|
||||
|
||||
public static DepositAccountInterestRateChartData template(Collection<EnumOptionData> periodTypes,
|
||||
final Collection<EnumOptionData> entityTypeOptions, final Collection<EnumOptionData> attributeNameOptions,
|
||||
final Collection<EnumOptionData> conditionTypeOptions, final Collection<EnumOptionData> incentiveTypeOptions,
|
||||
final Collection<CodeValueData> genderOptions, final Collection<CodeValueData> clientTypeOptions,
|
||||
final Collection<CodeValueData> clientClassificationOptions) {
|
||||
final Long id = null;
|
||||
final String name = null;
|
||||
final String description = null;
|
||||
final LocalDate fromDate = null;
|
||||
final LocalDate endDate = null;
|
||||
final Long accountId = null;
|
||||
final String accountNumber = null;
|
||||
final boolean isPrimaryGroupingByAmount = false;
|
||||
final Collection<DepositAccountInterestRateChartSlabData> chartSlabs = null;
|
||||
return new DepositAccountInterestRateChartData(id, name, description, fromDate, endDate, isPrimaryGroupingByAmount, accountId,
|
||||
accountNumber, chartSlabs, periodTypes, entityTypeOptions, attributeNameOptions, conditionTypeOptions, incentiveTypeOptions,
|
||||
genderOptions, clientTypeOptions, clientClassificationOptions);
|
||||
}
|
||||
|
||||
private DepositAccountInterestRateChartData(Long id, String name, String description, LocalDate fromDate, LocalDate endDate,
|
||||
final boolean isPrimaryGroupingByAmount, Long accountId, String accountNumber,
|
||||
Collection<DepositAccountInterestRateChartSlabData> chartSlabs, Collection<EnumOptionData> periodTypes,
|
||||
final Collection<EnumOptionData> entityTypeOptions, final Collection<EnumOptionData> attributeNameOptions,
|
||||
final Collection<EnumOptionData> conditionTypeOptions, final Collection<EnumOptionData> incentiveTypeOptions,
|
||||
final Collection<CodeValueData> genderOptions, final Collection<CodeValueData> clientTypeOptions,
|
||||
final Collection<CodeValueData> clientClassificationOptions) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.fromDate = fromDate;
|
||||
this.endDate = endDate;
|
||||
this.isPrimaryGroupingByAmount = isPrimaryGroupingByAmount;
|
||||
this.chartSlabs = chartSlabs;
|
||||
this.accountId = accountId;
|
||||
this.accountNumber = accountNumber;
|
||||
this.periodTypes = periodTypes;
|
||||
this.attributeNameOptions = attributeNameOptions;
|
||||
this.entityTypeOptions = entityTypeOptions;
|
||||
this.conditionTypeOptions = conditionTypeOptions;
|
||||
this.incentiveTypeOptions = incentiveTypeOptions;
|
||||
this.genderOptions = genderOptions;
|
||||
this.clientTypeOptions = clientTypeOptions;
|
||||
this.clientClassificationOptions = clientClassificationOptions;
|
||||
}
|
||||
|
||||
public void addChartSlab(final DepositAccountInterestRateChartSlabData chartSlab) {
|
||||
if (this.chartSlabs == null) {
|
||||
this.chartSlabs = new ArrayList<>();
|
||||
}
|
||||
this.chartSlabs.add(chartSlab);
|
||||
}
|
||||
|
||||
public boolean isFromDateAfter(final LocalDate compareDate) {
|
||||
return compareDate != null && DateUtils.isAfter(this.fromDate, compareDate);
|
||||
}
|
||||
|
||||
public LocalDate endDate() {
|
||||
return this.endDate;
|
||||
}
|
||||
|
||||
public LocalDate fromDate() {
|
||||
return this.fromDate;
|
||||
}
|
||||
}
|
||||
+146
@@ -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.savings.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.portfolio.interestratechart.data.InterestIncentiveData;
|
||||
import org.apache.fineract.portfolio.interestratechart.data.InterestRateChartSlabData;
|
||||
|
||||
/**
|
||||
* Immutable data object representing deposit accounts Interest rate Slabs.
|
||||
*/
|
||||
public final class DepositAccountInterestRateChartSlabData {
|
||||
|
||||
private final Long id;
|
||||
private final String description;
|
||||
private final EnumOptionData periodType;
|
||||
private final Integer fromPeriod;
|
||||
private final Integer toPeriod;
|
||||
private final BigDecimal amountRangeFrom;
|
||||
private final BigDecimal amountRangeTo;
|
||||
private final BigDecimal annualInterestRate;
|
||||
private final CurrencyData currency;
|
||||
|
||||
// associations
|
||||
private Collection<DepositAccountInterestIncentiveData> incentives;
|
||||
|
||||
// template
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<EnumOptionData> periodTypes;
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<EnumOptionData> entityTypeOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<EnumOptionData> attributeNameOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<EnumOptionData> conditionTypeOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<EnumOptionData> incentiveTypeOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<CodeValueData> genderOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<CodeValueData> clientTypeOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<CodeValueData> clientClassificationOptions;
|
||||
|
||||
public static DepositAccountInterestRateChartSlabData instance(final Long id, final String description, final EnumOptionData periodType,
|
||||
final Integer fromPeriod, final Integer toPeriod, final BigDecimal amountRangeFrom, final BigDecimal amountRangeTo,
|
||||
final BigDecimal annualInterestRate, final CurrencyData currency) {
|
||||
final Collection<EnumOptionData> periodTypes = null;
|
||||
final Collection<EnumOptionData> entityTypeOptions = null;
|
||||
final Collection<EnumOptionData> attributeNameOptions = null;
|
||||
final Collection<EnumOptionData> conditionTypeOptions = null;
|
||||
final Collection<EnumOptionData> incentiveTypeOptions = null;
|
||||
final Collection<CodeValueData> genderOptions = null;
|
||||
final Collection<CodeValueData> clientTypeOptions = null;
|
||||
final Collection<CodeValueData> clientClassificationOptions = null;
|
||||
final Collection<DepositAccountInterestIncentiveData> incentives = null;
|
||||
return new DepositAccountInterestRateChartSlabData(id, description, periodType, fromPeriod, toPeriod, amountRangeFrom,
|
||||
amountRangeTo, annualInterestRate, incentives, currency, periodTypes, entityTypeOptions, attributeNameOptions,
|
||||
conditionTypeOptions, incentiveTypeOptions, genderOptions, clientTypeOptions, clientClassificationOptions);
|
||||
}
|
||||
|
||||
public static DepositAccountInterestRateChartSlabData from(final InterestRateChartSlabData chartSlabData) {
|
||||
final Long id = null;
|
||||
Set<DepositAccountInterestIncentiveData> fromProdIncentives = new HashSet<>();
|
||||
Set<InterestIncentiveData> productIncentiveData = chartSlabData.incentives();
|
||||
if (productIncentiveData != null) {
|
||||
for (InterestIncentiveData incentive : productIncentiveData) {
|
||||
fromProdIncentives.add(DepositAccountInterestIncentiveData.from(incentive));
|
||||
}
|
||||
}
|
||||
return new DepositAccountInterestRateChartSlabData(id, chartSlabData.description(), chartSlabData.periodType(),
|
||||
chartSlabData.fromPeriod(), chartSlabData.toPeriod(), chartSlabData.amountRangeFrom(), chartSlabData.amountRangeTo(),
|
||||
chartSlabData.annualInterestRate(), fromProdIncentives, chartSlabData.currency(), chartSlabData.periodTypes(),
|
||||
chartSlabData.entityTypeOptions(), chartSlabData.attributeNameOptions(), chartSlabData.conditionTypeOptions(),
|
||||
chartSlabData.incentiveTypeOptions(), chartSlabData.genderOptions(), chartSlabData.clientTypeOptions(),
|
||||
chartSlabData.clientClassificationOptions());
|
||||
}
|
||||
|
||||
public static DepositAccountInterestRateChartSlabData withTemplate(final DepositAccountInterestRateChartSlabData chartSlab,
|
||||
final Collection<EnumOptionData> periodTypes, final Collection<EnumOptionData> entityTypeOptions,
|
||||
final Collection<EnumOptionData> attributeNameOptions, final Collection<EnumOptionData> conditionTypeOptions,
|
||||
final Collection<EnumOptionData> incentiveTypeOptions, final Collection<CodeValueData> genderOptions,
|
||||
final Collection<CodeValueData> clientTypeOptions, final Collection<CodeValueData> clientClassificationOptions) {
|
||||
return new DepositAccountInterestRateChartSlabData(chartSlab.id, chartSlab.description, chartSlab.periodType, chartSlab.fromPeriod,
|
||||
chartSlab.toPeriod, chartSlab.amountRangeFrom, chartSlab.amountRangeTo, chartSlab.annualInterestRate, chartSlab.incentives,
|
||||
chartSlab.currency, periodTypes, entityTypeOptions, attributeNameOptions, conditionTypeOptions, incentiveTypeOptions,
|
||||
genderOptions, clientTypeOptions, clientClassificationOptions);
|
||||
}
|
||||
|
||||
private DepositAccountInterestRateChartSlabData(final Long id, final String description, final EnumOptionData periodType,
|
||||
final Integer fromPeriod, final Integer toPeriod, final BigDecimal amountRangeFrom, final BigDecimal amountRangeTo,
|
||||
final BigDecimal annualInterestRate, final Collection<DepositAccountInterestIncentiveData> incentivesData,
|
||||
final CurrencyData currency, final Collection<EnumOptionData> periodTypes, final Collection<EnumOptionData> entityTypeOptions,
|
||||
final Collection<EnumOptionData> attributeNameOptions, final Collection<EnumOptionData> conditionTypeOptions,
|
||||
final Collection<EnumOptionData> incentiveTypeOptions, final Collection<CodeValueData> genderOptions,
|
||||
final Collection<CodeValueData> clientTypeOptions, final Collection<CodeValueData> clientClassificationOptions) {
|
||||
this.id = id;
|
||||
this.description = description;
|
||||
this.periodType = periodType;
|
||||
this.fromPeriod = fromPeriod;
|
||||
this.toPeriod = toPeriod;
|
||||
this.amountRangeFrom = amountRangeFrom;
|
||||
this.amountRangeTo = amountRangeTo;
|
||||
this.annualInterestRate = annualInterestRate;
|
||||
this.currency = currency;
|
||||
this.periodTypes = periodTypes;
|
||||
this.incentives = incentivesData;
|
||||
this.attributeNameOptions = attributeNameOptions;
|
||||
this.entityTypeOptions = entityTypeOptions;
|
||||
this.conditionTypeOptions = conditionTypeOptions;
|
||||
this.incentiveTypeOptions = incentiveTypeOptions;
|
||||
this.genderOptions = genderOptions;
|
||||
this.clientTypeOptions = clientTypeOptions;
|
||||
this.clientClassificationOptions = clientClassificationOptions;
|
||||
}
|
||||
|
||||
public void addIncentives(final DepositAccountInterestIncentiveData incentive) {
|
||||
if (this.incentives == null) {
|
||||
this.incentives = new HashSet<>();
|
||||
}
|
||||
this.incentives.add(incentive);
|
||||
}
|
||||
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
|
||||
public final class DepositAccountOnHoldTransactionData {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Long id;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal amount;
|
||||
@SuppressWarnings("unused")
|
||||
private EnumOptionData transactionType;
|
||||
@SuppressWarnings("unused")
|
||||
private final LocalDate transactionDate;
|
||||
@SuppressWarnings("unused")
|
||||
private final boolean reversed;
|
||||
@SuppressWarnings("unused")
|
||||
private final Long savingsId;
|
||||
@SuppressWarnings("unused")
|
||||
private final String savingsAccountNo;
|
||||
@SuppressWarnings("unused")
|
||||
private final String savingsClientName;
|
||||
@SuppressWarnings("unused")
|
||||
private final Long loanId;
|
||||
@SuppressWarnings("unused")
|
||||
private final String loanAccountNo;
|
||||
@SuppressWarnings("unused")
|
||||
private final String loanClientName;
|
||||
|
||||
private DepositAccountOnHoldTransactionData(final Long id, final BigDecimal amount, final EnumOptionData transactionType,
|
||||
final LocalDate transactionDate, final boolean reversed, final Long savingsId, final String savingsAccNo,
|
||||
final String savingsClientName, final Long loanId, final String loanAccNo, final String loanClientName) {
|
||||
this.id = id;
|
||||
this.amount = amount;
|
||||
this.transactionType = transactionType;
|
||||
this.transactionDate = transactionDate;
|
||||
this.reversed = reversed;
|
||||
this.savingsId = savingsId;
|
||||
this.savingsAccountNo = savingsAccNo;
|
||||
this.savingsClientName = savingsClientName;
|
||||
this.loanId = loanId;
|
||||
this.loanAccountNo = loanAccNo;
|
||||
this.loanClientName = loanClientName;
|
||||
}
|
||||
|
||||
private DepositAccountOnHoldTransactionData(final Long id, final BigDecimal amount, final EnumOptionData transactionType,
|
||||
final LocalDate transactionDate, final boolean reversed) {
|
||||
this.id = id;
|
||||
this.amount = amount;
|
||||
this.transactionType = transactionType;
|
||||
this.transactionDate = transactionDate;
|
||||
this.reversed = reversed;
|
||||
this.savingsAccountNo = null;
|
||||
this.savingsId = 0L;
|
||||
this.savingsClientName = null;
|
||||
this.loanId = 0L;
|
||||
this.loanAccountNo = null;
|
||||
this.loanClientName = null;
|
||||
}
|
||||
|
||||
public static DepositAccountOnHoldTransactionData instance(final Long id, final BigDecimal amount, final EnumOptionData transactionType,
|
||||
final LocalDate transactionDate, final boolean reversed, final Long savingsId, final String savingsAccountNo,
|
||||
final String savingsClientName, final Long loanId, final String loanAccountNo, final String loanClientName) {
|
||||
return new DepositAccountOnHoldTransactionData(id, amount, transactionType, transactionDate, reversed, savingsId, savingsAccountNo,
|
||||
savingsClientName, loanId, loanAccountNo, loanClientName);
|
||||
}
|
||||
|
||||
public static DepositAccountOnHoldTransactionData instance(Long transactionId, BigDecimal amount, EnumOptionData transactionType,
|
||||
LocalDate date, boolean transactionReversed) {
|
||||
return new DepositAccountOnHoldTransactionData(transactionId, amount, transactionType, date, transactionReversed);
|
||||
}
|
||||
}
|
||||
+456
@@ -0,0 +1,456 @@
|
||||
/**
|
||||
* 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.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.portfolio.charge.data.ChargeData;
|
||||
import org.apache.fineract.portfolio.interestratechart.data.InterestRateChartData;
|
||||
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
|
||||
import org.apache.fineract.portfolio.tax.data.TaxGroupData;
|
||||
|
||||
/**
|
||||
* Immutable data object represents a partial data of Deposit Proucts.
|
||||
*/
|
||||
public class DepositProductData {
|
||||
|
||||
protected final Long id;
|
||||
protected final String name;
|
||||
protected final String shortName;
|
||||
protected final String description;
|
||||
protected final CurrencyData currency;
|
||||
protected final BigDecimal nominalAnnualInterestRate;
|
||||
protected final EnumOptionData interestCompoundingPeriodType;
|
||||
protected final EnumOptionData interestPostingPeriodType;
|
||||
protected final EnumOptionData interestCalculationType;
|
||||
protected final EnumOptionData interestCalculationDaysInYearType;
|
||||
// protected final BigDecimal minRequiredOpeningBalance;
|
||||
protected final Integer lockinPeriodFrequency;
|
||||
protected final EnumOptionData lockinPeriodFrequencyType;
|
||||
// protected final boolean withdrawalFeeForTransfers;
|
||||
protected final BigDecimal minBalanceForInterestCalculation;
|
||||
protected final boolean withHoldTax;
|
||||
protected final TaxGroupData taxGroup;
|
||||
|
||||
// accounting
|
||||
protected final EnumOptionData accountingRule;
|
||||
protected final Map<String, Object> accountingMappings;
|
||||
protected final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings;
|
||||
protected final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings;
|
||||
protected final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings;
|
||||
|
||||
// charges
|
||||
protected final Collection<ChargeData> charges;
|
||||
|
||||
// interest rate charts
|
||||
protected final Collection<InterestRateChartData> interestRateCharts;
|
||||
protected final InterestRateChartData activeChart;
|
||||
|
||||
// template
|
||||
protected final Collection<CurrencyData> currencyOptions;
|
||||
protected final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions;
|
||||
protected final Collection<EnumOptionData> interestPostingPeriodTypeOptions;
|
||||
protected final Collection<EnumOptionData> interestCalculationTypeOptions;
|
||||
protected final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions;
|
||||
protected final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions;
|
||||
protected final Collection<EnumOptionData> withdrawalFeeTypeOptions;
|
||||
protected final Collection<PaymentTypeData> paymentTypeOptions;
|
||||
protected final Collection<EnumOptionData> accountingRuleOptions;
|
||||
protected final Map<String, List<GLAccountData>> accountingMappingOptions;
|
||||
protected final Collection<ChargeData> chargeOptions;
|
||||
protected final Collection<ChargeData> penaltyOptions;
|
||||
protected final InterestRateChartData chartTemplate;
|
||||
protected final Collection<TaxGroupData> taxGroupOptions;
|
||||
|
||||
public static DepositProductData template(final CurrencyData currency, final EnumOptionData interestCompoundingPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final EnumOptionData accountingRule,
|
||||
final Collection<CurrencyData> currencyOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<PaymentTypeData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> chargeOptions,
|
||||
final Collection<ChargeData> penaltyOptions, final InterestRateChartData chartTemplate,
|
||||
final Collection<TaxGroupData> taxGroupOptions) {
|
||||
|
||||
final Long id = null;
|
||||
final String name = null;
|
||||
final String shortName = null;
|
||||
final String description = null;
|
||||
final BigDecimal nominalAnnualInterestRate = null;
|
||||
final Integer lockinPeriodFrequency = null;
|
||||
final EnumOptionData lockinPeriodFrequencyType = null;
|
||||
final BigDecimal minBalanceForInterestCalculation = null;
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
final Collection<ChargeData> charges = null;
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings = null;
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings = null;
|
||||
final Collection<InterestRateChartData> interestRateCharts = null;
|
||||
final boolean withHoldTax = false;
|
||||
final TaxGroupData taxGroup = null;
|
||||
|
||||
return new DepositProductData(id, name, shortName, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, accountingRule, accountingMappings, paymentChannelToFundSourceMappings, currencyOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions,
|
||||
accountingRuleOptions, accountingMappingOptions, charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
|
||||
penaltyToIncomeAccountMappings, interestRateCharts, chartTemplate, minBalanceForInterestCalculation, withHoldTax, taxGroup,
|
||||
taxGroupOptions);
|
||||
}
|
||||
|
||||
public static DepositProductData withCharges(final DepositProductData existingProduct, final Collection<ChargeData> charges) {
|
||||
return new DepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description,
|
||||
existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
|
||||
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
existingProduct.interestCalculationDaysInYearType, existingProduct.lockinPeriodFrequency,
|
||||
existingProduct.lockinPeriodFrequencyType, existingProduct.accountingRule, existingProduct.accountingMappings,
|
||||
existingProduct.paymentChannelToFundSourceMappings, existingProduct.currencyOptions,
|
||||
existingProduct.interestCompoundingPeriodTypeOptions, existingProduct.interestPostingPeriodTypeOptions,
|
||||
existingProduct.interestCalculationTypeOptions, existingProduct.interestCalculationDaysInYearTypeOptions,
|
||||
existingProduct.lockinPeriodFrequencyTypeOptions, existingProduct.withdrawalFeeTypeOptions,
|
||||
existingProduct.paymentTypeOptions, existingProduct.accountingRuleOptions, existingProduct.accountingMappingOptions,
|
||||
charges, existingProduct.chargeOptions, existingProduct.penaltyOptions, existingProduct.feeToIncomeAccountMappings,
|
||||
existingProduct.penaltyToIncomeAccountMappings, existingProduct.interestRateCharts, existingProduct.chartTemplate,
|
||||
existingProduct.minBalanceForInterestCalculation, existingProduct.withHoldTax, existingProduct.taxGroup,
|
||||
existingProduct.taxGroupOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link DepositProductData} that contains and exist {@link DepositProductData} data with further
|
||||
* template data for dropdowns.
|
||||
*
|
||||
* @param taxGroupOptions
|
||||
* TODO
|
||||
*/
|
||||
public static DepositProductData withTemplate(final DepositProductData existingProduct, final Collection<CurrencyData> currencyOptions,
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<PaymentTypeData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> chargeOptions,
|
||||
final Collection<ChargeData> penaltyOptions, final InterestRateChartData chartTemplate,
|
||||
Collection<TaxGroupData> taxGroupOptions) {
|
||||
|
||||
return new DepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description,
|
||||
existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
|
||||
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
existingProduct.interestCalculationDaysInYearType, existingProduct.lockinPeriodFrequency,
|
||||
existingProduct.lockinPeriodFrequencyType, existingProduct.accountingRule, existingProduct.accountingMappings,
|
||||
existingProduct.paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
|
||||
accountingMappingOptions, existingProduct.charges, chargeOptions, penaltyOptions,
|
||||
existingProduct.feeToIncomeAccountMappings, existingProduct.penaltyToIncomeAccountMappings,
|
||||
existingProduct.interestRateCharts, chartTemplate, existingProduct.minBalanceForInterestCalculation,
|
||||
existingProduct.withHoldTax, existingProduct.taxGroup, taxGroupOptions);
|
||||
}
|
||||
|
||||
public static DepositProductData withAccountingDetails(final DepositProductData existingProduct,
|
||||
final Map<String, Object> accountingMappings, final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings,
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings,
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings) {
|
||||
|
||||
final Collection<CurrencyData> currencyOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = null;
|
||||
final Collection<EnumOptionData> accountingRuleOptions = null;
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final Collection<ChargeData> penaltyOptions = null;
|
||||
final Collection<TaxGroupData> taxGroupOptions = null;
|
||||
|
||||
return new DepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description,
|
||||
existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
|
||||
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
existingProduct.interestCalculationDaysInYearType, existingProduct.lockinPeriodFrequency,
|
||||
existingProduct.lockinPeriodFrequencyType, existingProduct.accountingRule, accountingMappings,
|
||||
paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, existingProduct.charges,
|
||||
chargeOptions, penaltyOptions, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings,
|
||||
existingProduct.interestRateCharts, existingProduct.chartTemplate, existingProduct.minBalanceForInterestCalculation,
|
||||
existingProduct.withHoldTax, existingProduct.taxGroup, taxGroupOptions);
|
||||
}
|
||||
|
||||
public static DepositProductData instance(final Long id, final String name, final String shortName, final String description,
|
||||
final CurrencyData currency, final BigDecimal nominalAnnualInterestRate, final EnumOptionData interestCompoundingPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final Integer lockinPeriodFrequency,
|
||||
final EnumOptionData lockinPeriodFrequencyType, final EnumOptionData accountingType,
|
||||
final BigDecimal minBalanceForInterestCalculation, boolean withHoldTax, TaxGroupData taxGroup) {
|
||||
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
|
||||
final Collection<CurrencyData> currencyOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = null;
|
||||
final Collection<EnumOptionData> accountingRuleOptions = null;
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final Collection<ChargeData> penaltyOptions = null;
|
||||
final Collection<ChargeData> charges = null;
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings = null;
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings = null;
|
||||
final Collection<InterestRateChartData> interestRateCharts = null;
|
||||
final InterestRateChartData chartTemplate = null;
|
||||
final Collection<TaxGroupData> taxGroupOptions = null;
|
||||
|
||||
return new DepositProductData(id, name, shortName, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, accountingType, accountingMappings, paymentChannelToFundSourceMappings, currencyOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions,
|
||||
accountingRuleOptions, accountingMappingOptions, charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
|
||||
penaltyToIncomeAccountMappings, interestRateCharts, chartTemplate, minBalanceForInterestCalculation, withHoldTax, taxGroup,
|
||||
taxGroupOptions);
|
||||
}
|
||||
|
||||
public static DepositProductData lookup(final Long id, final String name) {
|
||||
|
||||
final String shortName = null;
|
||||
final CurrencyData currency = null;
|
||||
final String description = null;
|
||||
final BigDecimal nominalAnnualInterestRate = null;
|
||||
final EnumOptionData interestCompoundingPeriodType = null;
|
||||
final EnumOptionData interestPostingPeriodType = null;
|
||||
final EnumOptionData interestCalculationType = null;
|
||||
final EnumOptionData interestCalculationDaysInYearType = null;
|
||||
final Integer lockinPeriodFrequency = null;
|
||||
final EnumOptionData lockinPeriodFrequencyType = null;
|
||||
final BigDecimal minBalanceForInterestCalculation = null;
|
||||
|
||||
final EnumOptionData accountingType = null;
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
|
||||
final Collection<CurrencyData> currencyOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = null;
|
||||
final Collection<EnumOptionData> accountingRuleOptions = null;
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions = null;
|
||||
final Collection<ChargeData> charges = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final Collection<ChargeData> penaltyOptions = null;
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings = null;
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings = null;
|
||||
final Collection<InterestRateChartData> interestRateCharts = null;
|
||||
final InterestRateChartData chartTemplate = null;
|
||||
final boolean withHoldTax = false;
|
||||
final TaxGroupData taxGroup = null;
|
||||
final Collection<TaxGroupData> taxGroupOptions = null;
|
||||
|
||||
return new DepositProductData(id, name, shortName, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, accountingType, accountingMappings, paymentChannelToFundSourceMappings, currencyOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions,
|
||||
accountingRuleOptions, accountingMappingOptions, charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
|
||||
penaltyToIncomeAccountMappings, interestRateCharts, chartTemplate, minBalanceForInterestCalculation, withHoldTax, taxGroup,
|
||||
taxGroupOptions);
|
||||
}
|
||||
|
||||
public static DepositProductData withInterestChart(final DepositProductData existingProduct,
|
||||
final Collection<InterestRateChartData> interestRateCharts) {
|
||||
return new DepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description,
|
||||
existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
|
||||
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
existingProduct.interestCalculationDaysInYearType, existingProduct.lockinPeriodFrequency,
|
||||
existingProduct.lockinPeriodFrequencyType, existingProduct.accountingRule, existingProduct.accountingMappings,
|
||||
existingProduct.paymentChannelToFundSourceMappings, existingProduct.currencyOptions,
|
||||
existingProduct.interestCompoundingPeriodTypeOptions, existingProduct.interestPostingPeriodTypeOptions,
|
||||
existingProduct.interestCalculationTypeOptions, existingProduct.interestCalculationDaysInYearTypeOptions,
|
||||
existingProduct.lockinPeriodFrequencyTypeOptions, existingProduct.withdrawalFeeTypeOptions,
|
||||
existingProduct.paymentTypeOptions, existingProduct.accountingRuleOptions, existingProduct.accountingMappingOptions,
|
||||
existingProduct.charges, existingProduct.chargeOptions, existingProduct.penaltyOptions,
|
||||
existingProduct.feeToIncomeAccountMappings, existingProduct.penaltyToIncomeAccountMappings, interestRateCharts,
|
||||
existingProduct.chartTemplate, existingProduct.minBalanceForInterestCalculation, existingProduct.withHoldTax,
|
||||
existingProduct.taxGroup, existingProduct.taxGroupOptions);
|
||||
}
|
||||
|
||||
protected DepositProductData(final Long id, final String name, final String shortName, final String description,
|
||||
final CurrencyData currency, final BigDecimal nominalAnnualInterestRate, final EnumOptionData interestCompoundingPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final Integer lockinPeriodFrequency,
|
||||
final EnumOptionData lockinPeriodFrequencyType, final EnumOptionData accountingType,
|
||||
final Map<String, Object> accountingMappings, final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings,
|
||||
final Collection<CurrencyData> currencyOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<PaymentTypeData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> charges,
|
||||
final Collection<ChargeData> chargeOptions, final Collection<ChargeData> penaltyOptions,
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings,
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings,
|
||||
final Collection<InterestRateChartData> interestRateCharts, final InterestRateChartData chartTemplate,
|
||||
final BigDecimal minBalanceForInterestCalculation, final boolean withHoldTax, final TaxGroupData taxGroup,
|
||||
final Collection<TaxGroupData> taxGroupOptions) {
|
||||
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.shortName = shortName;
|
||||
this.description = description;
|
||||
this.currency = currency;
|
||||
this.nominalAnnualInterestRate = nominalAnnualInterestRate;
|
||||
this.interestCompoundingPeriodType = interestCompoundingPeriodType;
|
||||
this.interestPostingPeriodType = interestPostingPeriodType;
|
||||
this.interestCalculationType = interestCalculationType;
|
||||
this.interestCalculationDaysInYearType = interestCalculationDaysInYearType;
|
||||
this.accountingRule = accountingType;
|
||||
this.lockinPeriodFrequency = lockinPeriodFrequency;
|
||||
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType;
|
||||
|
||||
this.currencyOptions = currencyOptions;
|
||||
this.interestCompoundingPeriodTypeOptions = interestCompoundingPeriodTypeOptions;
|
||||
this.interestPostingPeriodTypeOptions = interestPostingPeriodTypeOptions;
|
||||
this.interestCalculationTypeOptions = interestCalculationTypeOptions;
|
||||
this.interestCalculationDaysInYearTypeOptions = interestCalculationDaysInYearTypeOptions;
|
||||
this.lockinPeriodFrequencyTypeOptions = lockinPeriodFrequencyTypeOptions;
|
||||
this.withdrawalFeeTypeOptions = withdrawalFeeTypeOptions;
|
||||
|
||||
this.paymentTypeOptions = paymentTypeOptions;
|
||||
this.accountingMappingOptions = accountingMappingOptions;
|
||||
this.accountingRuleOptions = accountingRuleOptions;
|
||||
if (accountingMappings == null || accountingMappings.isEmpty()) {
|
||||
this.accountingMappings = null;
|
||||
} else {
|
||||
this.accountingMappings = accountingMappings;
|
||||
}
|
||||
this.paymentChannelToFundSourceMappings = paymentChannelToFundSourceMappings;
|
||||
|
||||
this.charges = charges;// charges associated with Savings product
|
||||
this.chargeOptions = chargeOptions;// charges available for adding to
|
||||
// Savings product
|
||||
this.penaltyOptions = penaltyOptions;// penalties available for adding
|
||||
// to Savings product
|
||||
|
||||
this.feeToIncomeAccountMappings = feeToIncomeAccountMappings;
|
||||
this.penaltyToIncomeAccountMappings = penaltyToIncomeAccountMappings;
|
||||
this.interestRateCharts = interestRateCharts;
|
||||
this.activeChart = activeChart(this.interestRateCharts);
|
||||
this.chartTemplate = chartTemplate;
|
||||
this.minBalanceForInterestCalculation = minBalanceForInterestCalculation;
|
||||
this.taxGroup = taxGroup;
|
||||
this.withHoldTax = withHoldTax;
|
||||
this.taxGroupOptions = taxGroupOptions;
|
||||
}
|
||||
|
||||
public static InterestRateChartData activeChart(Collection<InterestRateChartData> interestRateCharts) {
|
||||
InterestRateChartData activeChart = null;
|
||||
if (interestRateCharts != null) {
|
||||
for (InterestRateChartData chartData : interestRateCharts) {
|
||||
if (activeChart == null) {
|
||||
activeChart = chartData;
|
||||
} else {
|
||||
if (!activeChart.isFromDateAfter(chartData.endDate())) {
|
||||
activeChart = chartData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return activeChart;
|
||||
}
|
||||
|
||||
public boolean hasAccountingEnabled() {
|
||||
return this.accountingRule.getId() > AccountingRuleType.NONE.getValue();
|
||||
}
|
||||
|
||||
public int accountingRuleTypeId() {
|
||||
return this.accountingRule.getId().intValue();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public EnumOptionData getLockinPeriodFrequencyType() {
|
||||
return lockinPeriodFrequencyType;
|
||||
}
|
||||
|
||||
public Integer getLockinPeriodFrequency() {
|
||||
return lockinPeriodFrequency;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public BigDecimal getNominalAnnualInterestRate() {
|
||||
return nominalAnnualInterestRate;
|
||||
}
|
||||
|
||||
public EnumOptionData getInterestPostingPeriodType() {
|
||||
return interestPostingPeriodType;
|
||||
}
|
||||
|
||||
public EnumOptionData getInterestCalculationType() {
|
||||
return interestCalculationType;
|
||||
}
|
||||
|
||||
public EnumOptionData getInterestCalculationDaysInYearType() {
|
||||
return interestCalculationDaysInYearType;
|
||||
}
|
||||
|
||||
public BigDecimal getMinBalanceForInterestCalculation() {
|
||||
return minBalanceForInterestCalculation;
|
||||
}
|
||||
|
||||
public String getShortName() {
|
||||
return shortName;
|
||||
}
|
||||
|
||||
public CurrencyData getCurrency() {
|
||||
return currency;
|
||||
}
|
||||
|
||||
public EnumOptionData getInterestCompoundingPeriodType() {
|
||||
return interestCompoundingPeriodType;
|
||||
}
|
||||
}
|
||||
+544
@@ -0,0 +1,544 @@
|
||||
/**
|
||||
* 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.time.LocalDate;
|
||||
import java.util.Collection;
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.organisation.staff.data.StaffData;
|
||||
import org.apache.fineract.portfolio.account.data.PortfolioAccountData;
|
||||
import org.apache.fineract.portfolio.charge.data.ChargeData;
|
||||
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
|
||||
import org.apache.fineract.portfolio.savings.DepositAccountType;
|
||||
import org.apache.fineract.portfolio.savings.service.SavingsEnumerations;
|
||||
import org.apache.fineract.portfolio.tax.data.TaxGroupData;
|
||||
|
||||
/**
|
||||
* Immutable data object representing a Fixed Deposit account.
|
||||
*/
|
||||
@Getter
|
||||
public final class FixedDepositAccountData extends DepositAccountData {
|
||||
|
||||
private boolean preClosurePenalApplicable;
|
||||
private BigDecimal preClosurePenalInterest;
|
||||
private EnumOptionData preClosurePenalInterestOnType;
|
||||
private Integer minDepositTerm;
|
||||
private Integer maxDepositTerm;
|
||||
private EnumOptionData minDepositTermType;
|
||||
private EnumOptionData maxDepositTermType;
|
||||
private Integer inMultiplesOfDepositTerm;
|
||||
private EnumOptionData inMultiplesOfDepositTermType;
|
||||
private BigDecimal depositAmount;
|
||||
private BigDecimal maturityAmount;
|
||||
private LocalDate maturityDate;
|
||||
private Integer depositPeriod;
|
||||
private EnumOptionData depositPeriodFrequency;
|
||||
private BigDecimal activationCharge;
|
||||
private Long transferToSavingsId;
|
||||
|
||||
// used for account close
|
||||
private EnumOptionData onAccountClosure;
|
||||
|
||||
private final PortfolioAccountData linkedAccount;
|
||||
private final Boolean transferInterestToSavings;
|
||||
private final PortfolioAccountData transferToSavingsAccount;
|
||||
|
||||
private Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions;
|
||||
private Collection<EnumOptionData> periodFrequencyTypeOptions;
|
||||
private Collection<SavingsAccountData> savingsAccounts;
|
||||
|
||||
// for account close
|
||||
private Collection<EnumOptionData> onAccountClosureOptions;
|
||||
private Collection<PaymentTypeData> paymentTypeOptions;
|
||||
private final Collection<EnumOptionData> maturityInstructionOptions;
|
||||
|
||||
// import fields
|
||||
private transient Integer rowIndex;
|
||||
private String dateFormat;
|
||||
private String locale;
|
||||
private LocalDate submittedOnDate;
|
||||
private Long depositPeriodFrequencyId;
|
||||
|
||||
public static FixedDepositAccountData importInstance(Long clientId, Long productId, Long fieldOfficerId, LocalDate submittedOnDate,
|
||||
EnumOptionData interestCompoundingPeriodTypeEnum, EnumOptionData interestPostingPeriodTypeEnum,
|
||||
EnumOptionData interestCalculationTypeEnum, EnumOptionData interestCalculationDaysInYearTypeEnum, Integer lockinPeriodFrequency,
|
||||
EnumOptionData lockinPeriodFrequencyTypeEnum, BigDecimal depositAmount, Integer depositPeriod, Long depositPeriodFrequencyId,
|
||||
String externalId, Collection<SavingsAccountChargeData> charges, Integer rowIndex, String locale, String dateFormat) {
|
||||
|
||||
return new FixedDepositAccountData(clientId, productId, fieldOfficerId, submittedOnDate, interestCompoundingPeriodTypeEnum,
|
||||
interestPostingPeriodTypeEnum, interestCalculationTypeEnum, interestCalculationDaysInYearTypeEnum, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyTypeEnum, depositAmount, depositPeriod, depositPeriodFrequencyId, externalId, charges, rowIndex,
|
||||
locale, dateFormat);
|
||||
}
|
||||
|
||||
private FixedDepositAccountData(Long clientId, Long productId, Long fieldofficerId, LocalDate submittedOnDate,
|
||||
EnumOptionData interestCompoundingPeriodType, EnumOptionData interestPostingPeriodType, EnumOptionData interestCalculationType,
|
||||
EnumOptionData interestCalculationDaysInYearType, Integer lockinPeriodFrequency, EnumOptionData lockinPeriodFrequencyType,
|
||||
BigDecimal depositAmount, Integer depositPeriod, Long depositPeriodFrequencyId, String externalId,
|
||||
Collection<SavingsAccountChargeData> charges, Integer rowIndex, String locale, String dateFormat) {
|
||||
super(clientId, productId, fieldofficerId, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType,
|
||||
interestCalculationDaysInYearType, lockinPeriodFrequency, lockinPeriodFrequencyType, externalId, charges);
|
||||
this.preClosurePenalApplicable = false;
|
||||
this.preClosurePenalInterest = null;
|
||||
this.preClosurePenalInterestOnType = null;
|
||||
this.minDepositTerm = null;
|
||||
this.maxDepositTerm = null;
|
||||
this.minDepositTermType = null;
|
||||
this.maxDepositTermType = null;
|
||||
this.inMultiplesOfDepositTerm = null;
|
||||
this.inMultiplesOfDepositTermType = null;
|
||||
this.depositAmount = depositAmount;
|
||||
this.maturityAmount = null;
|
||||
this.maturityDate = null;
|
||||
this.depositPeriod = depositPeriod;
|
||||
this.depositPeriodFrequency = null;
|
||||
this.activationCharge = null;
|
||||
this.onAccountClosure = null;
|
||||
this.linkedAccount = null;
|
||||
this.transferToSavingsAccount = null;
|
||||
this.transferInterestToSavings = null;
|
||||
this.preClosurePenalInterestOnTypeOptions = null;
|
||||
this.periodFrequencyTypeOptions = null;
|
||||
this.savingsAccounts = null;
|
||||
this.onAccountClosureOptions = null;
|
||||
this.paymentTypeOptions = null;
|
||||
this.rowIndex = rowIndex;
|
||||
this.dateFormat = dateFormat;
|
||||
this.locale = locale;
|
||||
this.submittedOnDate = submittedOnDate;
|
||||
this.depositPeriodFrequencyId = depositPeriodFrequencyId;
|
||||
this.maturityInstructionOptions = null;
|
||||
}
|
||||
|
||||
public static FixedDepositAccountData instance(final DepositAccountData depositAccountData, final boolean preClosurePenalApplicable,
|
||||
final BigDecimal preClosurePenalInterest, final EnumOptionData preClosurePenalInterestOnType, final Integer minDepositTerm,
|
||||
final Integer maxDepositTerm, final EnumOptionData minDepositTermType, final EnumOptionData maxDepositTermType,
|
||||
final Integer inMultiplesOfDepositTerm, final EnumOptionData inMultiplesOfDepositTermType, final BigDecimal depositAmount,
|
||||
final BigDecimal maturityAmount, final LocalDate maturityDate, final Integer depositPeriod,
|
||||
final EnumOptionData depositPeriodFrequency, final EnumOptionData onAccountClosure, final Boolean transferInterestToSavings,
|
||||
final Long transferToSavingsId) {
|
||||
|
||||
final PortfolioAccountData linkedAccount = null;
|
||||
final PortfolioAccountData transferToSavingsAccount = null;
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null;
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> maturityInstructionOptions = null;
|
||||
|
||||
final EnumOptionData depositType = SavingsEnumerations.depositType(DepositAccountType.FIXED_DEPOSIT.getValue());
|
||||
final Collection<EnumOptionData> onAccountClosureOptions = null;
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = null;
|
||||
final Collection<SavingsAccountData> savingsAccountDatas = null;
|
||||
|
||||
return new FixedDepositAccountData(depositAccountData.id, depositAccountData.accountNo, depositAccountData.externalId,
|
||||
depositAccountData.groupId, depositAccountData.groupName, depositAccountData.clientId, depositAccountData.clientName,
|
||||
depositAccountData.depositProductId, depositAccountData.depositProductName, depositAccountData.fieldOfficerId,
|
||||
depositAccountData.fieldOfficerName, depositAccountData.status, depositAccountData.timeline, depositAccountData.currency,
|
||||
depositAccountData.nominalAnnualInterestRate, depositAccountData.interestCompoundingPeriodType,
|
||||
depositAccountData.interestPostingPeriodType, depositAccountData.interestCalculationType,
|
||||
depositAccountData.interestCalculationDaysInYearType, depositAccountData.minRequiredOpeningBalance,
|
||||
depositAccountData.lockinPeriodFrequency, depositAccountData.lockinPeriodFrequencyType,
|
||||
depositAccountData.withdrawalFeeForTransfers, depositAccountData.minBalanceForInterestCalculation,
|
||||
depositAccountData.summary, depositAccountData.transactions, depositAccountData.productOptions,
|
||||
depositAccountData.fieldOfficerOptions, depositAccountData.interestCompoundingPeriodTypeOptions,
|
||||
depositAccountData.interestPostingPeriodTypeOptions, depositAccountData.interestCalculationTypeOptions,
|
||||
depositAccountData.interestCalculationDaysInYearTypeOptions, depositAccountData.lockinPeriodFrequencyTypeOptions,
|
||||
depositAccountData.withdrawalFeeTypeOptions, depositAccountData.charges, depositAccountData.chargeOptions,
|
||||
depositAccountData.accountChart, depositAccountData.chartTemplate, preClosurePenalApplicable, preClosurePenalInterest,
|
||||
preClosurePenalInterestOnType, preClosurePenalInterestOnTypeOptions, minDepositTerm, maxDepositTerm, minDepositTermType,
|
||||
maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, depositAmount, maturityAmount, maturityDate,
|
||||
depositPeriod, depositPeriodFrequency, periodFrequencyTypeOptions, depositType, onAccountClosure, onAccountClosureOptions,
|
||||
paymentTypeOptions, savingsAccountDatas, linkedAccount, transferInterestToSavings, depositAccountData.withHoldTax,
|
||||
depositAccountData.taxGroup, maturityInstructionOptions, transferToSavingsId, transferToSavingsAccount);
|
||||
}
|
||||
|
||||
public static FixedDepositAccountData withInterestChart(final FixedDepositAccountData account,
|
||||
final DepositAccountInterestRateChartData accountChart) {
|
||||
return new FixedDepositAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
||||
account.clientId, account.clientName, account.depositProductId, account.depositProductName, account.fieldOfficerId,
|
||||
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
||||
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
||||
account.interestCalculationDaysInYearType, account.minRequiredOpeningBalance, account.lockinPeriodFrequency,
|
||||
account.lockinPeriodFrequencyType, account.withdrawalFeeForTransfers, account.minBalanceForInterestCalculation,
|
||||
account.summary, account.transactions, account.productOptions, account.fieldOfficerOptions,
|
||||
account.interestCompoundingPeriodTypeOptions, account.interestPostingPeriodTypeOptions,
|
||||
account.interestCalculationTypeOptions, account.interestCalculationDaysInYearTypeOptions,
|
||||
account.lockinPeriodFrequencyTypeOptions, account.withdrawalFeeTypeOptions, account.charges, account.chargeOptions,
|
||||
accountChart, account.chartTemplate, account.preClosurePenalApplicable, account.preClosurePenalInterest,
|
||||
account.preClosurePenalInterestOnType, account.preClosurePenalInterestOnTypeOptions, account.minDepositTerm,
|
||||
account.maxDepositTerm, account.minDepositTermType, account.maxDepositTermType, account.inMultiplesOfDepositTerm,
|
||||
account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount, account.maturityDate,
|
||||
account.depositPeriod, account.depositPeriodFrequency, account.periodFrequencyTypeOptions, account.depositType,
|
||||
account.onAccountClosure, account.onAccountClosureOptions, account.paymentTypeOptions, account.savingsAccounts,
|
||||
account.linkedAccount, account.transferInterestToSavings, account.withHoldTax, account.taxGroup,
|
||||
account.maturityInstructionOptions, account.transferToSavingsId, account.transferToSavingsAccount);
|
||||
}
|
||||
|
||||
public static FixedDepositAccountData associationsAndTemplate(final FixedDepositAccountData account, FixedDepositAccountData template,
|
||||
final Collection<SavingsAccountTransactionData> transactions, final Collection<SavingsAccountChargeData> charges,
|
||||
final PortfolioAccountData linkedAccount, PortfolioAccountData transferToSavingsAccount) {
|
||||
|
||||
if (template == null) {
|
||||
template = account;
|
||||
}
|
||||
|
||||
return new FixedDepositAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
||||
account.clientId, account.clientName, account.depositProductId, account.depositProductName, account.fieldOfficerId,
|
||||
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
||||
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
||||
account.interestCalculationDaysInYearType, account.minRequiredOpeningBalance, account.lockinPeriodFrequency,
|
||||
account.lockinPeriodFrequencyType, account.withdrawalFeeForTransfers, account.minBalanceForInterestCalculation,
|
||||
account.summary, transactions, template.productOptions, template.fieldOfficerOptions,
|
||||
template.interestCompoundingPeriodTypeOptions, template.interestPostingPeriodTypeOptions,
|
||||
template.interestCalculationTypeOptions, template.interestCalculationDaysInYearTypeOptions,
|
||||
template.lockinPeriodFrequencyTypeOptions, template.withdrawalFeeTypeOptions, charges, template.chargeOptions,
|
||||
account.accountChart, account.chartTemplate, account.preClosurePenalApplicable, account.preClosurePenalInterest,
|
||||
account.preClosurePenalInterestOnType, template.preClosurePenalInterestOnTypeOptions, account.minDepositTerm,
|
||||
account.maxDepositTerm, account.minDepositTermType, account.maxDepositTermType, account.inMultiplesOfDepositTerm,
|
||||
account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount, account.maturityDate,
|
||||
account.depositPeriod, account.depositPeriodFrequency, template.periodFrequencyTypeOptions, account.depositType,
|
||||
account.onAccountClosure, account.onAccountClosureOptions, account.paymentTypeOptions, template.savingsAccounts,
|
||||
linkedAccount, account.transferInterestToSavings, account.withHoldTax, account.taxGroup, account.maturityInstructionOptions,
|
||||
account.transferToSavingsId, transferToSavingsAccount);
|
||||
}
|
||||
|
||||
public static FixedDepositAccountData withTemplateOptions(final FixedDepositAccountData account,
|
||||
final Collection<DepositProductData> productOptions, final Collection<StaffData> fieldOfficerOptions,
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<SavingsAccountTransactionData> transactions, final Collection<SavingsAccountChargeData> charges,
|
||||
final Collection<ChargeData> chargeOptions, final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions,
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions, final Collection<SavingsAccountData> savingsAccounts,
|
||||
final Collection<EnumOptionData> maturityInstructionOptions) {
|
||||
|
||||
return new FixedDepositAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
||||
account.clientId, account.clientName, account.depositProductId, account.depositProductName, account.fieldOfficerId,
|
||||
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
||||
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
||||
account.interestCalculationDaysInYearType, account.minRequiredOpeningBalance, account.lockinPeriodFrequency,
|
||||
account.lockinPeriodFrequencyType, account.withdrawalFeeForTransfers, account.minBalanceForInterestCalculation,
|
||||
account.summary, transactions, productOptions, fieldOfficerOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, charges, chargeOptions, account.accountChart,
|
||||
account.chartTemplate, account.preClosurePenalApplicable, account.preClosurePenalInterest,
|
||||
account.preClosurePenalInterestOnType, preClosurePenalInterestOnTypeOptions, account.minDepositTerm, account.maxDepositTerm,
|
||||
account.minDepositTermType, account.maxDepositTermType, account.inMultiplesOfDepositTerm,
|
||||
account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount, account.maturityDate,
|
||||
account.depositPeriod, account.depositPeriodFrequency, periodFrequencyTypeOptions, account.depositType,
|
||||
account.onAccountClosure, account.onAccountClosureOptions, account.paymentTypeOptions, savingsAccounts,
|
||||
account.linkedAccount, account.transferInterestToSavings, account.withHoldTax, account.taxGroup, maturityInstructionOptions,
|
||||
account.transferToSavingsId, account.transferToSavingsAccount);
|
||||
}
|
||||
|
||||
public static FixedDepositAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId,
|
||||
final String groupName) {
|
||||
|
||||
final Long id = null;
|
||||
final String accountNo = null;
|
||||
final String externalId = null;
|
||||
final Long productId = null;
|
||||
final String productName = null;
|
||||
final Long fieldOfficerId = null;
|
||||
final String fieldOfficerName = null;
|
||||
final SavingsAccountStatusEnumData status = null;
|
||||
final SavingsAccountApplicationTimelineData timeline = null;
|
||||
final CurrencyData currency = null;
|
||||
final BigDecimal nominalAnnualInterestRate = null;
|
||||
final EnumOptionData interestPeriodType = null;
|
||||
final EnumOptionData interestPostingPeriodType = null;
|
||||
final EnumOptionData interestCalculationType = null;
|
||||
final EnumOptionData interestCalculationDaysInYearType = null;
|
||||
final BigDecimal minRequiredOpeningBalance = null;
|
||||
final Integer lockinPeriodFrequency = null;
|
||||
final EnumOptionData lockinPeriodFrequencyType = null;
|
||||
final boolean withdrawalFeeForTransfers = false;
|
||||
final BigDecimal minBalanceForInterestCalculation = null;
|
||||
final SavingsAccountSummaryData summary = null;
|
||||
final Collection<SavingsAccountTransactionData> transactions = null;
|
||||
final boolean withHoldTax = false;
|
||||
final TaxGroupData taxGroup = null;
|
||||
|
||||
final Collection<DepositProductData> productOptions = null;
|
||||
final Collection<StaffData> fieldOfficerOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
|
||||
final Collection<SavingsAccountChargeData> charges = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
|
||||
final DepositAccountInterestRateChartData accountChart = null;
|
||||
final DepositAccountInterestRateChartData chartTemplate = null;
|
||||
final boolean preClosurePenalApplicable = false;
|
||||
final BigDecimal preClosurePenalInterest = null;
|
||||
final EnumOptionData preClosurePenalInterestOnType = null;
|
||||
final Integer minDepositTerm = null;
|
||||
final Integer maxDepositTerm = null;
|
||||
final EnumOptionData minDepositTermType = null;
|
||||
final EnumOptionData maxDepositTermType = null;
|
||||
final Integer inMultiplesOfDepositTerm = null;
|
||||
final EnumOptionData inMultiplesOfDepositTermType = null;
|
||||
final BigDecimal depositAmount = null;
|
||||
final BigDecimal maturityAmount = null;
|
||||
final LocalDate maturityDate = null;
|
||||
final Integer depositPeriod = null;
|
||||
final EnumOptionData depositPeriodFrequency = null;
|
||||
final EnumOptionData onAccountClosure = null;
|
||||
final PortfolioAccountData linkedAccount = null;
|
||||
final PortfolioAccountData transferToSavingsAccount = null;
|
||||
final Boolean transferInterestToSavings = null;
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null;
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions = null;
|
||||
|
||||
final EnumOptionData depositType = SavingsEnumerations.depositType(DepositAccountType.FIXED_DEPOSIT.getValue());
|
||||
final Collection<EnumOptionData> onAccountClosureOptions = null;
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = null;
|
||||
final Collection<SavingsAccountData> savingsAccountDatas = null;
|
||||
final Collection<EnumOptionData> maturityInstructionOptions = null;
|
||||
final Long transferToSavingsId = null;
|
||||
|
||||
return new FixedDepositAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
|
||||
fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate, interestPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, minBalanceForInterestCalculation, summary,
|
||||
transactions, productOptions, fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, charges, chargeOptions, accountChart, chartTemplate, preClosurePenalApplicable,
|
||||
preClosurePenalInterest, preClosurePenalInterestOnType, preClosurePenalInterestOnTypeOptions, minDepositTerm,
|
||||
maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType,
|
||||
depositAmount, maturityAmount, maturityDate, depositPeriod, depositPeriodFrequency, periodFrequencyTypeOptions, depositType,
|
||||
onAccountClosure, onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas, linkedAccount,
|
||||
transferInterestToSavings, withHoldTax, taxGroup, maturityInstructionOptions, transferToSavingsId,
|
||||
transferToSavingsAccount);
|
||||
}
|
||||
|
||||
public static FixedDepositAccountData preClosureDetails(final Long accountId, BigDecimal maturityAmount,
|
||||
final Collection<EnumOptionData> onAccountClosureOptions, final Collection<PaymentTypeData> paymentTypeOptions,
|
||||
final Collection<SavingsAccountData> savingsAccountDatas) {
|
||||
|
||||
final Long groupId = null;
|
||||
final String groupName = null;
|
||||
final Long clientId = null;
|
||||
final String clientName = null;
|
||||
final String accountNo = null;
|
||||
final String externalId = null;
|
||||
final Long productId = null;
|
||||
final String productName = null;
|
||||
final Long fieldOfficerId = null;
|
||||
final String fieldOfficerName = null;
|
||||
final SavingsAccountStatusEnumData status = null;
|
||||
final SavingsAccountApplicationTimelineData timeline = null;
|
||||
final CurrencyData currency = null;
|
||||
final BigDecimal nominalAnnualInterestRate = null;
|
||||
final EnumOptionData interestPeriodType = null;
|
||||
final EnumOptionData interestPostingPeriodType = null;
|
||||
final EnumOptionData interestCalculationType = null;
|
||||
final EnumOptionData interestCalculationDaysInYearType = null;
|
||||
final BigDecimal minRequiredOpeningBalance = null;
|
||||
final Integer lockinPeriodFrequency = null;
|
||||
final EnumOptionData lockinPeriodFrequencyType = null;
|
||||
final boolean withdrawalFeeForTransfers = false;
|
||||
final BigDecimal minBalanceForInterestCalculation = null;
|
||||
final SavingsAccountSummaryData summary = null;
|
||||
final Collection<SavingsAccountTransactionData> transactions = null;
|
||||
final Collection<DepositProductData> productOptions = null;
|
||||
final Collection<StaffData> fieldOfficerOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
|
||||
final Collection<SavingsAccountChargeData> charges = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
|
||||
final DepositAccountInterestRateChartData accountChart = null;
|
||||
final DepositAccountInterestRateChartData chartTemplate = null;
|
||||
final boolean preClosurePenalApplicable = false;
|
||||
final BigDecimal preClosurePenalInterest = null;
|
||||
final EnumOptionData preClosurePenalInterestOnType = null;
|
||||
final Integer minDepositTerm = null;
|
||||
final Integer maxDepositTerm = null;
|
||||
final EnumOptionData minDepositTermType = null;
|
||||
final EnumOptionData maxDepositTermType = null;
|
||||
final Integer inMultiplesOfDepositTerm = null;
|
||||
final EnumOptionData inMultiplesOfDepositTermType = null;
|
||||
final BigDecimal depositAmount = null;
|
||||
final LocalDate maturityDate = null;
|
||||
final Integer depositPeriod = null;
|
||||
final EnumOptionData depositPeriodFrequency = null;
|
||||
final EnumOptionData onAccountClosure = null;
|
||||
final Boolean transferInterestToSavings = null;
|
||||
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null;
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions = null;
|
||||
|
||||
final EnumOptionData depositType = SavingsEnumerations.depositType(DepositAccountType.FIXED_DEPOSIT.getValue());
|
||||
final PortfolioAccountData linkedAccount = null;
|
||||
final boolean withHoldTax = false;
|
||||
final TaxGroupData taxGroup = null;
|
||||
final Collection<EnumOptionData> maturityInstructionOptions = null;
|
||||
final Long transferToSavingsId = null;
|
||||
final PortfolioAccountData transferToSavingsAccount = null;
|
||||
|
||||
return new FixedDepositAccountData(accountId, accountNo, externalId, groupId, groupName, clientId, clientName, productId,
|
||||
productName, fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate, interestPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, minBalanceForInterestCalculation, summary,
|
||||
transactions, productOptions, fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, charges, chargeOptions, accountChart, chartTemplate, preClosurePenalApplicable,
|
||||
preClosurePenalInterest, preClosurePenalInterestOnType, preClosurePenalInterestOnTypeOptions, minDepositTerm,
|
||||
maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType,
|
||||
depositAmount, maturityAmount, maturityDate, depositPeriod, depositPeriodFrequency, periodFrequencyTypeOptions, depositType,
|
||||
onAccountClosure, onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas, linkedAccount,
|
||||
transferInterestToSavings, withHoldTax, taxGroup, maturityInstructionOptions, transferToSavingsId,
|
||||
transferToSavingsAccount);
|
||||
}
|
||||
|
||||
public static FixedDepositAccountData withClosureTemplateDetails(final FixedDepositAccountData account,
|
||||
final Collection<EnumOptionData> onAccountClosureOptions, final Collection<PaymentTypeData> paymentTypeOptions,
|
||||
final Collection<SavingsAccountData> savingsAccountDatas) {
|
||||
|
||||
return new FixedDepositAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
||||
account.clientId, account.clientName, account.depositProductId, account.depositProductName, account.fieldOfficerId,
|
||||
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
||||
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
||||
account.interestCalculationDaysInYearType, account.minRequiredOpeningBalance, account.lockinPeriodFrequency,
|
||||
account.lockinPeriodFrequencyType, account.withdrawalFeeForTransfers, account.minBalanceForInterestCalculation,
|
||||
account.summary, account.transactions, account.productOptions, account.fieldOfficerOptions,
|
||||
account.interestCompoundingPeriodTypeOptions, account.interestPostingPeriodTypeOptions,
|
||||
account.interestCalculationTypeOptions, account.interestCalculationDaysInYearTypeOptions,
|
||||
account.lockinPeriodFrequencyTypeOptions, account.withdrawalFeeTypeOptions, account.charges, account.chargeOptions,
|
||||
account.accountChart, account.chartTemplate, account.preClosurePenalApplicable, account.preClosurePenalInterest,
|
||||
account.preClosurePenalInterestOnType, account.preClosurePenalInterestOnTypeOptions, account.minDepositTerm,
|
||||
account.maxDepositTerm, account.minDepositTermType, account.maxDepositTermType, account.inMultiplesOfDepositTerm,
|
||||
account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount, account.maturityDate,
|
||||
account.depositPeriod, account.depositPeriodFrequency, account.periodFrequencyTypeOptions, account.depositType,
|
||||
account.onAccountClosure, onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas, account.linkedAccount,
|
||||
account.transferInterestToSavings, account.withHoldTax, account.taxGroup, account.maturityInstructionOptions,
|
||||
account.transferToSavingsId, account.transferToSavingsAccount);
|
||||
|
||||
}
|
||||
|
||||
private FixedDepositAccountData(final Long id, final String accountNo, final String externalId, final Long groupId,
|
||||
final String groupName, final Long clientId, final String clientName, final Long productId, final String productName,
|
||||
final Long fieldofficerId, final String fieldofficerName, final SavingsAccountStatusEnumData status,
|
||||
final SavingsAccountApplicationTimelineData timeline, final CurrencyData currency, final BigDecimal nominalAnnualInterestRate,
|
||||
final EnumOptionData interestPeriodType, final EnumOptionData interestPostingPeriodType,
|
||||
final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType,
|
||||
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType,
|
||||
final boolean withdrawalFeeForTransfers, final BigDecimal minBalanceForInterestCalculation,
|
||||
final SavingsAccountSummaryData summary, final Collection<SavingsAccountTransactionData> transactions,
|
||||
final Collection<DepositProductData> productOptions, final Collection<StaffData> fieldOfficerOptions,
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<SavingsAccountChargeData> charges, final Collection<ChargeData> chargeOptions,
|
||||
final DepositAccountInterestRateChartData accountChart, final DepositAccountInterestRateChartData chartTemplate,
|
||||
final boolean preClosurePenalApplicable, final BigDecimal preClosurePenalInterest,
|
||||
final EnumOptionData preClosurePenalInterestOnType, final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions,
|
||||
final Integer minDepositTerm, final Integer maxDepositTerm, final EnumOptionData minDepositTermType,
|
||||
final EnumOptionData maxDepositTermType, final Integer inMultiplesOfDepositTerm,
|
||||
final EnumOptionData inMultiplesOfDepositTermType, final BigDecimal depositAmount, final BigDecimal maturityAmount,
|
||||
final LocalDate maturityDate, final Integer depositPeriod, final EnumOptionData depositPeriodFrequency,
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions, final EnumOptionData depositType,
|
||||
final EnumOptionData onAccountClosure, final Collection<EnumOptionData> onAccountClosureOptions,
|
||||
final Collection<PaymentTypeData> paymentTypeOptions, final Collection<SavingsAccountData> savingsAccountDatas,
|
||||
final PortfolioAccountData linkedAccount, final Boolean transferInterestToSavings, final boolean withHoldTax,
|
||||
final TaxGroupData taxGroup, final Collection<EnumOptionData> maturityInstructionOptions, final Long transferToSavingsId,
|
||||
final PortfolioAccountData transferToSavingsAccount) {
|
||||
|
||||
super(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName, fieldofficerId, fieldofficerName,
|
||||
status, timeline, currency, nominalAnnualInterestRate, interestPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary, transactions, productOptions, fieldOfficerOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, charges,
|
||||
chargeOptions, accountChart, chartTemplate, depositType, minBalanceForInterestCalculation, withHoldTax, taxGroup);
|
||||
|
||||
this.preClosurePenalApplicable = preClosurePenalApplicable;
|
||||
this.preClosurePenalInterest = preClosurePenalInterest;
|
||||
this.preClosurePenalInterestOnType = preClosurePenalInterestOnType;
|
||||
this.minDepositTerm = minDepositTerm;
|
||||
this.maxDepositTerm = maxDepositTerm;
|
||||
this.minDepositTermType = minDepositTermType;
|
||||
this.maxDepositTermType = maxDepositTermType;
|
||||
this.inMultiplesOfDepositTerm = inMultiplesOfDepositTerm;
|
||||
this.inMultiplesOfDepositTermType = inMultiplesOfDepositTermType;
|
||||
this.depositAmount = depositAmount;
|
||||
this.maturityAmount = maturityAmount;
|
||||
this.maturityDate = maturityDate;
|
||||
this.depositPeriod = depositPeriod;
|
||||
this.depositPeriodFrequency = depositPeriodFrequency;
|
||||
this.onAccountClosure = onAccountClosure;
|
||||
this.linkedAccount = linkedAccount;
|
||||
this.transferToSavingsAccount = transferToSavingsAccount;
|
||||
this.transferInterestToSavings = transferInterestToSavings;
|
||||
|
||||
// template
|
||||
this.preClosurePenalInterestOnTypeOptions = preClosurePenalInterestOnTypeOptions;
|
||||
this.periodFrequencyTypeOptions = periodFrequencyTypeOptions;
|
||||
|
||||
// account close template options
|
||||
this.onAccountClosureOptions = onAccountClosureOptions;
|
||||
this.paymentTypeOptions = paymentTypeOptions;
|
||||
this.savingsAccounts = savingsAccountDatas;
|
||||
this.maturityInstructionOptions = maturityInstructionOptions;
|
||||
this.transferToSavingsId = transferToSavingsId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof FixedDepositAccountData)) {
|
||||
return false;
|
||||
}
|
||||
final FixedDepositAccountData rhs = (FixedDepositAccountData) obj;
|
||||
return new EqualsBuilder().append(this.id, rhs.id).append(this.accountNo, rhs.accountNo).isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37).append(this.id).append(this.accountNo).toHashCode();
|
||||
}
|
||||
|
||||
public void setActivationCharge(BigDecimal activationCharge) {
|
||||
this.activationCharge = activationCharge;
|
||||
}
|
||||
}
|
||||
+448
@@ -0,0 +1,448 @@
|
||||
/**
|
||||
* 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.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.portfolio.charge.data.ChargeData;
|
||||
import org.apache.fineract.portfolio.interestratechart.data.InterestRateChartData;
|
||||
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
|
||||
import org.apache.fineract.portfolio.tax.data.TaxGroupData;
|
||||
|
||||
/**
|
||||
* Immutable data object representing a Fixed Deposit product.
|
||||
*/
|
||||
public final class FixedDepositProductData extends DepositProductData {
|
||||
|
||||
// additional fields
|
||||
private boolean preClosurePenalApplicable;
|
||||
private BigDecimal preClosurePenalInterest;
|
||||
private EnumOptionData preClosurePenalInterestOnType;
|
||||
private Integer minDepositTerm;
|
||||
private Integer maxDepositTerm;
|
||||
private EnumOptionData minDepositTermType;
|
||||
private EnumOptionData maxDepositTermType;
|
||||
private Integer inMultiplesOfDepositTerm;
|
||||
private EnumOptionData inMultiplesOfDepositTermType;
|
||||
private BigDecimal minDepositAmount;
|
||||
private BigDecimal depositAmount;
|
||||
private BigDecimal maxDepositAmount;
|
||||
|
||||
private Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions;
|
||||
private Collection<EnumOptionData> periodFrequencyTypeOptions;
|
||||
|
||||
public static FixedDepositProductData template(final CurrencyData currency, final EnumOptionData interestCompoundingPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final EnumOptionData accountingRule,
|
||||
final Collection<CurrencyData> currencyOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<PaymentTypeData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> chargeOptions,
|
||||
final Collection<ChargeData> penaltyOptions, final InterestRateChartData chartTemplate,
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions,
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions, final Collection<TaxGroupData> taxGroupOptions) {
|
||||
|
||||
final Long id = null;
|
||||
final String name = null;
|
||||
final String shortName = null;
|
||||
final String description = null;
|
||||
final BigDecimal nominalAnnualInterestRate = null;
|
||||
final Integer lockinPeriodFrequency = null;
|
||||
final EnumOptionData lockinPeriodFrequencyType = null;
|
||||
final BigDecimal minBalanceForInterestCalculation = null;
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
final Collection<ChargeData> charges = null;
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings = null;
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings = null;
|
||||
final Collection<InterestRateChartData> interestRateCharts = null;
|
||||
|
||||
final boolean preClosurePenalApplicable = false;
|
||||
final BigDecimal preClosurePenalInterest = null;
|
||||
final EnumOptionData preClosurePenalInterestOnType = null;
|
||||
final Integer minDepositTerm = null;
|
||||
final Integer maxDepositTerm = null;
|
||||
final EnumOptionData minDepositTermType = null;
|
||||
final EnumOptionData maxDepositTermType = null;
|
||||
final Integer inMultiplesOfDepositTerm = null;
|
||||
final EnumOptionData inMultiplesOfDepositTermType = null;
|
||||
final BigDecimal minDepositAmount = null;
|
||||
final BigDecimal depositAmount = null;
|
||||
final BigDecimal maxDepositAmount = null;
|
||||
final boolean withHoldTax = false;
|
||||
final TaxGroupData taxGroup = null;
|
||||
|
||||
return new FixedDepositProductData(id, name, shortName, description, currency, nominalAnnualInterestRate,
|
||||
interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, minBalanceForInterestCalculation, accountingRule, accountingMappings,
|
||||
paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, charges, chargeOptions,
|
||||
penaltyOptions, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, interestRateCharts, chartTemplate,
|
||||
preClosurePenalApplicable, preClosurePenalInterest, preClosurePenalInterestOnType, preClosurePenalInterestOnTypeOptions,
|
||||
minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm,
|
||||
inMultiplesOfDepositTermType, minDepositAmount, depositAmount, maxDepositAmount, periodFrequencyTypeOptions, withHoldTax,
|
||||
taxGroup, taxGroupOptions);
|
||||
}
|
||||
|
||||
public static FixedDepositProductData withCharges(final FixedDepositProductData existingProduct, final Collection<ChargeData> charges) {
|
||||
return new FixedDepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description,
|
||||
existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
|
||||
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
existingProduct.interestCalculationDaysInYearType, existingProduct.lockinPeriodFrequency,
|
||||
existingProduct.lockinPeriodFrequencyType, existingProduct.minBalanceForInterestCalculation, existingProduct.accountingRule,
|
||||
existingProduct.accountingMappings, existingProduct.paymentChannelToFundSourceMappings, existingProduct.currencyOptions,
|
||||
existingProduct.interestCompoundingPeriodTypeOptions, existingProduct.interestPostingPeriodTypeOptions,
|
||||
existingProduct.interestCalculationTypeOptions, existingProduct.interestCalculationDaysInYearTypeOptions,
|
||||
existingProduct.lockinPeriodFrequencyTypeOptions, existingProduct.withdrawalFeeTypeOptions,
|
||||
existingProduct.paymentTypeOptions, existingProduct.accountingRuleOptions, existingProduct.accountingMappingOptions,
|
||||
charges, existingProduct.chargeOptions, existingProduct.penaltyOptions, existingProduct.feeToIncomeAccountMappings,
|
||||
existingProduct.penaltyToIncomeAccountMappings, existingProduct.interestRateCharts, existingProduct.chartTemplate,
|
||||
existingProduct.preClosurePenalApplicable, existingProduct.preClosurePenalInterest,
|
||||
existingProduct.preClosurePenalInterestOnType, existingProduct.preClosurePenalInterestOnTypeOptions,
|
||||
existingProduct.minDepositTerm, existingProduct.maxDepositTerm, existingProduct.minDepositTermType,
|
||||
existingProduct.maxDepositTermType, existingProduct.inMultiplesOfDepositTerm, existingProduct.inMultiplesOfDepositTermType,
|
||||
existingProduct.minDepositAmount, existingProduct.depositAmount, existingProduct.maxDepositAmount,
|
||||
existingProduct.periodFrequencyTypeOptions, existingProduct.withHoldTax, existingProduct.taxGroup,
|
||||
existingProduct.taxGroupOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link FixedDepositProductData} that contains and exist {@link FixedDepositProductData} data with
|
||||
* further template data for dropdowns.
|
||||
*
|
||||
* @param taxGroupOptions
|
||||
* TODO
|
||||
*/
|
||||
public static FixedDepositProductData withTemplate(final FixedDepositProductData existingProduct,
|
||||
final Collection<CurrencyData> currencyOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<PaymentTypeData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> chargeOptions,
|
||||
final Collection<ChargeData> penaltyOptions, final InterestRateChartData chartTemplate,
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions,
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions, final Collection<TaxGroupData> taxGroupOptions) {
|
||||
|
||||
return new FixedDepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description,
|
||||
existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
|
||||
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
existingProduct.interestCalculationDaysInYearType, existingProduct.lockinPeriodFrequency,
|
||||
existingProduct.lockinPeriodFrequencyType, existingProduct.minBalanceForInterestCalculation, existingProduct.accountingRule,
|
||||
existingProduct.accountingMappings, existingProduct.paymentChannelToFundSourceMappings, currencyOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions,
|
||||
accountingRuleOptions, accountingMappingOptions, existingProduct.charges, chargeOptions, penaltyOptions,
|
||||
existingProduct.feeToIncomeAccountMappings, existingProduct.penaltyToIncomeAccountMappings,
|
||||
existingProduct.interestRateCharts, chartTemplate, existingProduct.preClosurePenalApplicable,
|
||||
existingProduct.preClosurePenalInterest, existingProduct.preClosurePenalInterestOnType,
|
||||
preClosurePenalInterestOnTypeOptions, existingProduct.minDepositTerm, existingProduct.maxDepositTerm,
|
||||
existingProduct.minDepositTermType, existingProduct.maxDepositTermType, existingProduct.inMultiplesOfDepositTerm,
|
||||
existingProduct.inMultiplesOfDepositTermType, existingProduct.minDepositAmount, existingProduct.depositAmount,
|
||||
existingProduct.maxDepositAmount, periodFrequencyTypeOptions, existingProduct.withHoldTax, existingProduct.taxGroup,
|
||||
taxGroupOptions);
|
||||
}
|
||||
|
||||
public static FixedDepositProductData withAccountingDetails(final FixedDepositProductData existingProduct,
|
||||
final Map<String, Object> accountingMappings, final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings,
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings,
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings) {
|
||||
|
||||
final Collection<CurrencyData> currencyOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = null;
|
||||
final Collection<EnumOptionData> accountingRuleOptions = null;
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final Collection<ChargeData> penaltyOptions = null;
|
||||
|
||||
return new FixedDepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description,
|
||||
existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
|
||||
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
existingProduct.interestCalculationDaysInYearType, existingProduct.lockinPeriodFrequency,
|
||||
existingProduct.lockinPeriodFrequencyType, existingProduct.minBalanceForInterestCalculation, existingProduct.accountingRule,
|
||||
accountingMappings, paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
|
||||
accountingMappingOptions, existingProduct.charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
|
||||
penaltyToIncomeAccountMappings, existingProduct.interestRateCharts, existingProduct.chartTemplate,
|
||||
existingProduct.preClosurePenalApplicable, existingProduct.preClosurePenalInterest,
|
||||
existingProduct.preClosurePenalInterestOnType, existingProduct.preClosurePenalInterestOnTypeOptions,
|
||||
existingProduct.minDepositTerm, existingProduct.maxDepositTerm, existingProduct.minDepositTermType,
|
||||
existingProduct.maxDepositTermType, existingProduct.inMultiplesOfDepositTerm, existingProduct.inMultiplesOfDepositTermType,
|
||||
existingProduct.minDepositAmount, existingProduct.depositAmount, existingProduct.maxDepositAmount,
|
||||
existingProduct.periodFrequencyTypeOptions, existingProduct.withHoldTax, existingProduct.taxGroup,
|
||||
existingProduct.taxGroupOptions);
|
||||
}
|
||||
|
||||
public static FixedDepositProductData instance(final DepositProductData depositProductData, final boolean preClosurePenalApplicable,
|
||||
final BigDecimal preClosurePenalInterest, final EnumOptionData preClosurePenalInterestOnType, final Integer minDepositTerm,
|
||||
final Integer maxDepositTerm, final EnumOptionData minDepositTermType, final EnumOptionData maxDepositTermType,
|
||||
final Integer inMultiplesOfDepositTerm, final EnumOptionData inMultiplesOfDepositTermType, final BigDecimal minDepositAmount,
|
||||
final BigDecimal depositAmount, final BigDecimal maxDepositAmount) {
|
||||
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
|
||||
final Collection<CurrencyData> currencyOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = null;
|
||||
final Collection<EnumOptionData> accountingRuleOptions = null;
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final Collection<ChargeData> penaltyOptions = null;
|
||||
final Collection<ChargeData> charges = null;
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings = null;
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings = null;
|
||||
final Collection<InterestRateChartData> interestRateCharts = null;
|
||||
final InterestRateChartData chartTemplate = null;
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null;
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions = null;
|
||||
final Collection<TaxGroupData> taxGroupOptions = null;
|
||||
|
||||
return new FixedDepositProductData(depositProductData.id, depositProductData.name, depositProductData.shortName,
|
||||
depositProductData.description, depositProductData.currency, depositProductData.nominalAnnualInterestRate,
|
||||
depositProductData.interestCompoundingPeriodType, depositProductData.interestPostingPeriodType,
|
||||
depositProductData.interestCalculationType, depositProductData.interestCalculationDaysInYearType,
|
||||
depositProductData.lockinPeriodFrequency, depositProductData.lockinPeriodFrequencyType,
|
||||
depositProductData.minBalanceForInterestCalculation, depositProductData.accountingRule, accountingMappings,
|
||||
paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, charges, chargeOptions,
|
||||
penaltyOptions, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, interestRateCharts, chartTemplate,
|
||||
preClosurePenalApplicable, preClosurePenalInterest, preClosurePenalInterestOnType, preClosurePenalInterestOnTypeOptions,
|
||||
minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm,
|
||||
inMultiplesOfDepositTermType, minDepositAmount, depositAmount, maxDepositAmount, periodFrequencyTypeOptions,
|
||||
depositProductData.withHoldTax, depositProductData.taxGroup, taxGroupOptions);
|
||||
}
|
||||
|
||||
public static FixedDepositProductData lookup(final Long id, final String name) {
|
||||
|
||||
final String shortName = null;
|
||||
final CurrencyData currency = null;
|
||||
final String description = null;
|
||||
final BigDecimal nominalAnnualInterestRate = null;
|
||||
final EnumOptionData interestCompoundingPeriodType = null;
|
||||
final EnumOptionData interestPostingPeriodType = null;
|
||||
final EnumOptionData interestCalculationType = null;
|
||||
final EnumOptionData interestCalculationDaysInYearType = null;
|
||||
final Integer lockinPeriodFrequency = null;
|
||||
final EnumOptionData lockinPeriodFrequencyType = null;
|
||||
final BigDecimal minBalanceForInterestCalculation = null;
|
||||
final EnumOptionData accountingType = null;
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
|
||||
final Collection<CurrencyData> currencyOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = null;
|
||||
final Collection<EnumOptionData> accountingRuleOptions = null;
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions = null;
|
||||
final Collection<ChargeData> charges = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final Collection<ChargeData> penaltyOptions = null;
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings = null;
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings = null;
|
||||
final Collection<InterestRateChartData> interestRateCharts = null;
|
||||
final InterestRateChartData chartTemplate = null;
|
||||
final boolean preClosurePenalApplicable = false;
|
||||
final BigDecimal preClosurePenalInterest = null;
|
||||
final EnumOptionData preClosurePenalInterestOnType = null;
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null;
|
||||
final Integer minDepositTerm = null;
|
||||
final Integer maxDepositTerm = null;
|
||||
final EnumOptionData minDepositTermType = null;
|
||||
final EnumOptionData maxDepositTermType = null;
|
||||
final Integer inMultiplesOfDepositTerm = null;
|
||||
final EnumOptionData inMultiplesOfDepositTermType = null;
|
||||
final BigDecimal minDepositAmount = null;
|
||||
final BigDecimal depositAmount = null;
|
||||
final BigDecimal maxDepositAmount = null;
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions = null;
|
||||
final boolean withHoldTax = false;
|
||||
final TaxGroupData taxGroup = null;
|
||||
final Collection<TaxGroupData> taxGroupOptions = null;
|
||||
|
||||
return new FixedDepositProductData(id, name, shortName, description, currency, nominalAnnualInterestRate,
|
||||
interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, minBalanceForInterestCalculation, accountingType, accountingMappings,
|
||||
paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, charges, chargeOptions,
|
||||
penaltyOptions, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, interestRateCharts, chartTemplate,
|
||||
preClosurePenalApplicable, preClosurePenalInterest, preClosurePenalInterestOnType, preClosurePenalInterestOnTypeOptions,
|
||||
minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm,
|
||||
inMultiplesOfDepositTermType, minDepositAmount, depositAmount, maxDepositAmount, periodFrequencyTypeOptions, withHoldTax,
|
||||
taxGroup, taxGroupOptions);
|
||||
}
|
||||
|
||||
public static FixedDepositProductData withInterestChart(final FixedDepositProductData existingProduct,
|
||||
final Collection<InterestRateChartData> interestRateCharts) {
|
||||
return new FixedDepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description,
|
||||
existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
|
||||
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
existingProduct.interestCalculationDaysInYearType, existingProduct.lockinPeriodFrequency,
|
||||
existingProduct.lockinPeriodFrequencyType, existingProduct.minBalanceForInterestCalculation, existingProduct.accountingRule,
|
||||
existingProduct.accountingMappings, existingProduct.paymentChannelToFundSourceMappings, existingProduct.currencyOptions,
|
||||
existingProduct.interestCompoundingPeriodTypeOptions, existingProduct.interestPostingPeriodTypeOptions,
|
||||
existingProduct.interestCalculationTypeOptions, existingProduct.interestCalculationDaysInYearTypeOptions,
|
||||
existingProduct.lockinPeriodFrequencyTypeOptions, existingProduct.withdrawalFeeTypeOptions,
|
||||
existingProduct.paymentTypeOptions, existingProduct.accountingRuleOptions, existingProduct.accountingMappingOptions,
|
||||
existingProduct.charges, existingProduct.chargeOptions, existingProduct.penaltyOptions,
|
||||
existingProduct.feeToIncomeAccountMappings, existingProduct.penaltyToIncomeAccountMappings, interestRateCharts,
|
||||
existingProduct.chartTemplate, existingProduct.preClosurePenalApplicable, existingProduct.preClosurePenalInterest,
|
||||
existingProduct.preClosurePenalInterestOnType, existingProduct.preClosurePenalInterestOnTypeOptions,
|
||||
existingProduct.minDepositTerm, existingProduct.maxDepositTerm, existingProduct.minDepositTermType,
|
||||
existingProduct.maxDepositTermType, existingProduct.inMultiplesOfDepositTerm, existingProduct.inMultiplesOfDepositTermType,
|
||||
existingProduct.minDepositAmount, existingProduct.depositAmount, existingProduct.maxDepositAmount,
|
||||
existingProduct.periodFrequencyTypeOptions, existingProduct.withHoldTax, existingProduct.taxGroup,
|
||||
existingProduct.taxGroupOptions);
|
||||
|
||||
}
|
||||
|
||||
private FixedDepositProductData(final Long id, final String name, final String shortName, final String description,
|
||||
final CurrencyData currency, final BigDecimal nominalAnnualInterestRate, final EnumOptionData interestCompoundingPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final Integer lockinPeriodFrequency,
|
||||
final EnumOptionData lockinPeriodFrequencyType, final BigDecimal minBalanceForInterestCalculation,
|
||||
final EnumOptionData accountingType, final Map<String, Object> accountingMappings,
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings,
|
||||
final Collection<CurrencyData> currencyOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<PaymentTypeData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> charges,
|
||||
final Collection<ChargeData> chargeOptions, final Collection<ChargeData> penaltyOptions,
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings,
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings,
|
||||
final Collection<InterestRateChartData> interestRateCharts, final InterestRateChartData chartTemplate,
|
||||
final boolean preClosurePenalApplicable, final BigDecimal preClosurePenalInterest,
|
||||
final EnumOptionData preClosurePenalInterestOnType, final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions,
|
||||
final Integer minDepositTerm, final Integer maxDepositTerm, final EnumOptionData minDepositTermType,
|
||||
final EnumOptionData maxDepositTermType, final Integer inMultiplesOfDepositTerm,
|
||||
final EnumOptionData inMultiplesOfDepositTermType, final BigDecimal minDepositAmount, final BigDecimal depositAmount,
|
||||
final BigDecimal maxDepositAmount, final Collection<EnumOptionData> periodFrequencyTypeOptions, final boolean withHoldTax,
|
||||
final TaxGroupData taxGroup, final Collection<TaxGroupData> taxGroupOptions) {
|
||||
|
||||
super(id, name, shortName, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, accountingType, accountingMappings, paymentChannelToFundSourceMappings, currencyOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions,
|
||||
accountingRuleOptions, accountingMappingOptions, charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
|
||||
penaltyToIncomeAccountMappings, interestRateCharts, chartTemplate, minBalanceForInterestCalculation, withHoldTax, taxGroup,
|
||||
taxGroupOptions);
|
||||
|
||||
// fixed deposit additional fields
|
||||
this.preClosurePenalApplicable = preClosurePenalApplicable;
|
||||
this.preClosurePenalInterest = preClosurePenalInterest;
|
||||
this.preClosurePenalInterestOnType = preClosurePenalInterestOnType;
|
||||
this.minDepositTerm = minDepositTerm;
|
||||
this.maxDepositTerm = maxDepositTerm;
|
||||
this.minDepositTermType = minDepositTermType;
|
||||
this.maxDepositTermType = maxDepositTermType;
|
||||
this.inMultiplesOfDepositTerm = inMultiplesOfDepositTerm;
|
||||
this.inMultiplesOfDepositTermType = inMultiplesOfDepositTermType;
|
||||
this.minDepositAmount = minDepositAmount;
|
||||
this.depositAmount = depositAmount;
|
||||
this.maxDepositAmount = maxDepositAmount;
|
||||
|
||||
// template
|
||||
this.preClosurePenalInterestOnTypeOptions = preClosurePenalInterestOnTypeOptions;
|
||||
this.periodFrequencyTypeOptions = periodFrequencyTypeOptions;
|
||||
}
|
||||
|
||||
public Integer getMinDepositTerm() {
|
||||
return minDepositTerm;
|
||||
}
|
||||
|
||||
public EnumOptionData getMinDepositTermType() {
|
||||
return minDepositTermType;
|
||||
}
|
||||
|
||||
public EnumOptionData getMaxDepositTermType() {
|
||||
return maxDepositTermType;
|
||||
}
|
||||
|
||||
public Integer getMaxDepositTerm() {
|
||||
return maxDepositTerm;
|
||||
}
|
||||
|
||||
public Integer getInMultiplesOfDepositTerm() {
|
||||
return inMultiplesOfDepositTerm;
|
||||
}
|
||||
|
||||
public EnumOptionData getInMultiplesOfDepositTermType() {
|
||||
return inMultiplesOfDepositTermType;
|
||||
}
|
||||
|
||||
public BigDecimal getMinDepositAmount() {
|
||||
return minDepositAmount;
|
||||
}
|
||||
|
||||
public BigDecimal getDepositAmount() {
|
||||
return depositAmount;
|
||||
}
|
||||
|
||||
public BigDecimal getMaxDepositAmount() {
|
||||
return maxDepositAmount;
|
||||
}
|
||||
|
||||
public EnumOptionData getPreClosurePenalInterestOnType() {
|
||||
return preClosurePenalInterestOnType;
|
||||
}
|
||||
|
||||
public BigDecimal getPreClosurePenalInterest() {
|
||||
return preClosurePenalInterest;
|
||||
}
|
||||
|
||||
public boolean isPreClosurePenalApplicable() {
|
||||
return preClosurePenalApplicable;
|
||||
}
|
||||
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* 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 final 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;
|
||||
}
|
||||
|
||||
}
|
||||
+614
@@ -0,0 +1,614 @@
|
||||
/**
|
||||
* 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.time.LocalDate;
|
||||
import java.util.Collection;
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.organisation.staff.data.StaffData;
|
||||
import org.apache.fineract.portfolio.charge.data.ChargeData;
|
||||
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
|
||||
import org.apache.fineract.portfolio.savings.DepositAccountType;
|
||||
import org.apache.fineract.portfolio.savings.service.SavingsEnumerations;
|
||||
import org.apache.fineract.portfolio.tax.data.TaxGroupData;
|
||||
|
||||
/**
|
||||
* Immutable data object representing a Recurring Deposit account.
|
||||
*/
|
||||
@Getter
|
||||
public final class RecurringDepositAccountData extends DepositAccountData {
|
||||
|
||||
// additional fields
|
||||
private final boolean preClosurePenalApplicable;
|
||||
private final BigDecimal preClosurePenalInterest;
|
||||
private final EnumOptionData preClosurePenalInterestOnType;
|
||||
private final Integer minDepositTerm;
|
||||
private final Integer maxDepositTerm;
|
||||
private final EnumOptionData minDepositTermType;
|
||||
private final EnumOptionData maxDepositTermType;
|
||||
private final Integer inMultiplesOfDepositTerm;
|
||||
private final EnumOptionData inMultiplesOfDepositTermType;
|
||||
private final BigDecimal depositAmount;
|
||||
private final BigDecimal maturityAmount;
|
||||
private final LocalDate maturityDate;
|
||||
private final Integer depositPeriod;
|
||||
private final EnumOptionData depositPeriodFrequency;
|
||||
private final BigDecimal mandatoryRecommendedDepositAmount;
|
||||
private final BigDecimal totalOverdueAmount;
|
||||
private final Integer noOfOverdueInstallments;
|
||||
private final boolean isMandatoryDeposit;
|
||||
private final boolean allowWithdrawal;
|
||||
private final boolean adjustAdvanceTowardsFuturePayments;
|
||||
private final LocalDate expectedFirstDepositOnDate;
|
||||
private final boolean isCalendarInherited;
|
||||
private final Integer recurringFrequency;
|
||||
private final EnumOptionData recurringFrequencyType;
|
||||
|
||||
// used for account close
|
||||
private final EnumOptionData onAccountClosure;
|
||||
|
||||
private final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions;
|
||||
private final Collection<EnumOptionData> periodFrequencyTypeOptions;
|
||||
private final Collection<SavingsAccountData> savingsAccounts;
|
||||
|
||||
// for account close
|
||||
private final Collection<EnumOptionData> onAccountClosureOptions;
|
||||
private final Collection<PaymentTypeData> paymentTypeOptions;
|
||||
|
||||
// import fields
|
||||
private transient Integer rowIndex;
|
||||
private String dateFormat;
|
||||
private String locale;
|
||||
private LocalDate submittedOnDate;
|
||||
private Long depositPeriodFrequencyId;
|
||||
|
||||
public static RecurringDepositAccountData importInstance(Long clientId, Long productId, Long fieldOfficerId, LocalDate submittedOnDate,
|
||||
EnumOptionData interestCompoundingPeriodTypeEnum, EnumOptionData interestPostingPeriodTypeEnum,
|
||||
EnumOptionData interestCalculationTypeEnum, EnumOptionData interestCalculationDaysInYearTypeEnum, Integer lockinPeriodFrequency,
|
||||
EnumOptionData lockinPeriodFrequencyTypeEnum, BigDecimal depositAmount, Integer depositPeriod, Long depositPeriodFrequencyId,
|
||||
LocalDate expectedFirstDepositOnDate, Integer recurringFrequency, EnumOptionData recurringFrequencyTypeEnum,
|
||||
boolean isCalendarInherited, boolean isMandatoryDeposit, boolean allowWithdrawal, boolean adjustAdvanceTowardsFuturePayments,
|
||||
String externalId, Collection<SavingsAccountChargeData> charges, Integer rowIndex, String locale, String dateFormat) {
|
||||
|
||||
return new RecurringDepositAccountData(clientId, productId, fieldOfficerId, submittedOnDate, interestCompoundingPeriodTypeEnum,
|
||||
interestPostingPeriodTypeEnum, interestCalculationTypeEnum, interestCalculationDaysInYearTypeEnum, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyTypeEnum, depositAmount, depositPeriod, depositPeriodFrequencyId, expectedFirstDepositOnDate,
|
||||
recurringFrequency, recurringFrequencyTypeEnum, isCalendarInherited, isMandatoryDeposit, allowWithdrawal,
|
||||
adjustAdvanceTowardsFuturePayments, externalId, charges, rowIndex, locale, dateFormat);
|
||||
}
|
||||
|
||||
private RecurringDepositAccountData(Long clientId, Long productId, Long fieldofficerId, LocalDate submittedOnDate,
|
||||
EnumOptionData interestCompoundingPeriodType, EnumOptionData interestPostingPeriodType, EnumOptionData interestCalculationType,
|
||||
EnumOptionData interestCalculationDaysInYearType, Integer lockinPeriodFrequency, EnumOptionData lockinPeriodFrequencyType,
|
||||
BigDecimal depositAmount, Integer depositPeriod, Long depositPeriodFrequencyId, LocalDate expectedFirstDepositOnDate,
|
||||
Integer recurringFrequency, EnumOptionData recurringFrequencyType, boolean isCalendarInherited, boolean isMandatoryDeposit,
|
||||
boolean allowWithdrawal, boolean adjustAdvanceTowardsFuturePayments, String externalId,
|
||||
Collection<SavingsAccountChargeData> charges, Integer rowIndex, String locale, String dateFormat) {
|
||||
super(clientId, productId, fieldofficerId, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType,
|
||||
interestCalculationDaysInYearType, lockinPeriodFrequency, lockinPeriodFrequencyType, externalId, charges);
|
||||
|
||||
this.preClosurePenalApplicable = false;
|
||||
this.preClosurePenalInterest = null;
|
||||
this.preClosurePenalInterestOnType = null;
|
||||
this.minDepositTerm = null;
|
||||
this.maxDepositTerm = null;
|
||||
this.minDepositTermType = null;
|
||||
this.maxDepositTermType = null;
|
||||
this.inMultiplesOfDepositTerm = null;
|
||||
this.inMultiplesOfDepositTermType = null;
|
||||
this.depositAmount = null;
|
||||
this.maturityAmount = null;
|
||||
this.maturityDate = null;
|
||||
this.depositPeriod = depositPeriod;
|
||||
this.depositPeriodFrequency = null;
|
||||
this.mandatoryRecommendedDepositAmount = depositAmount;
|
||||
this.totalOverdueAmount = null;
|
||||
this.noOfOverdueInstallments = null;
|
||||
this.isMandatoryDeposit = isMandatoryDeposit;
|
||||
this.allowWithdrawal = allowWithdrawal;
|
||||
this.adjustAdvanceTowardsFuturePayments = adjustAdvanceTowardsFuturePayments;
|
||||
this.expectedFirstDepositOnDate = expectedFirstDepositOnDate;
|
||||
this.isCalendarInherited = isCalendarInherited;
|
||||
this.recurringFrequency = recurringFrequency;
|
||||
this.recurringFrequencyType = recurringFrequencyType;
|
||||
this.onAccountClosure = null;
|
||||
this.preClosurePenalInterestOnTypeOptions = null;
|
||||
this.periodFrequencyTypeOptions = null;
|
||||
this.savingsAccounts = null;
|
||||
this.onAccountClosureOptions = null;
|
||||
this.paymentTypeOptions = null;
|
||||
this.rowIndex = rowIndex;
|
||||
this.dateFormat = dateFormat;
|
||||
this.locale = locale;
|
||||
this.submittedOnDate = submittedOnDate;
|
||||
this.depositPeriodFrequencyId = depositPeriodFrequencyId;
|
||||
}
|
||||
|
||||
public Integer getRowIndex() {
|
||||
return rowIndex;
|
||||
}
|
||||
|
||||
public static RecurringDepositAccountData instance(final DepositAccountData depositAccountData, final boolean preClosurePenalApplicable,
|
||||
final BigDecimal preClosurePenalInterest, final EnumOptionData preClosurePenalInterestOnType, final Integer minDepositTerm,
|
||||
final Integer maxDepositTerm, final EnumOptionData minDepositTermType, final EnumOptionData maxDepositTermType,
|
||||
final Integer inMultiplesOfDepositTerm, final EnumOptionData inMultiplesOfDepositTermType, final BigDecimal depositAmount,
|
||||
final BigDecimal maturityAmount, final LocalDate maturityDate, final Integer depositPeriod,
|
||||
final EnumOptionData depositPeriodFrequency, final BigDecimal mandatoryRecommendedDepositAmount,
|
||||
final EnumOptionData onAccountClosure, final LocalDate expectedFirstDepositOnDate, final BigDecimal totalOverdueAmount,
|
||||
final Integer noOfOverdueInstallments, final boolean isMandatoryDeposit, final boolean allowWithdrawal,
|
||||
final boolean adjustAdvanceTowardsFuturePayments, final boolean isCalendarInherited) {
|
||||
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null;
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions = null;
|
||||
|
||||
final EnumOptionData depositType = SavingsEnumerations.depositType(DepositAccountType.FIXED_DEPOSIT.getValue());
|
||||
final Collection<EnumOptionData> onAccountClosureOptions = null;
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = null;
|
||||
final Collection<SavingsAccountData> savingsAccountDatas = null;
|
||||
final Integer recurringFrequency = null;
|
||||
final EnumOptionData recurringFrequencyType = null;
|
||||
|
||||
return new RecurringDepositAccountData(depositAccountData.id, depositAccountData.accountNo, depositAccountData.externalId,
|
||||
depositAccountData.groupId, depositAccountData.groupName, depositAccountData.clientId, depositAccountData.clientName,
|
||||
depositAccountData.depositProductId, depositAccountData.depositProductName, depositAccountData.fieldOfficerId,
|
||||
depositAccountData.fieldOfficerName, depositAccountData.status, depositAccountData.timeline, depositAccountData.currency,
|
||||
depositAccountData.nominalAnnualInterestRate, depositAccountData.interestCompoundingPeriodType,
|
||||
depositAccountData.interestPostingPeriodType, depositAccountData.interestCalculationType,
|
||||
depositAccountData.interestCalculationDaysInYearType, depositAccountData.minRequiredOpeningBalance,
|
||||
depositAccountData.lockinPeriodFrequency, depositAccountData.lockinPeriodFrequencyType,
|
||||
depositAccountData.withdrawalFeeForTransfers, depositAccountData.minBalanceForInterestCalculation,
|
||||
depositAccountData.summary, depositAccountData.transactions, depositAccountData.productOptions,
|
||||
depositAccountData.fieldOfficerOptions, depositAccountData.interestCompoundingPeriodTypeOptions,
|
||||
depositAccountData.interestPostingPeriodTypeOptions, depositAccountData.interestCalculationTypeOptions,
|
||||
depositAccountData.interestCalculationDaysInYearTypeOptions, depositAccountData.lockinPeriodFrequencyTypeOptions,
|
||||
depositAccountData.withdrawalFeeTypeOptions, depositAccountData.charges, depositAccountData.chargeOptions,
|
||||
depositAccountData.accountChart, depositAccountData.chartTemplate, preClosurePenalApplicable, preClosurePenalInterest,
|
||||
preClosurePenalInterestOnType, preClosurePenalInterestOnTypeOptions, minDepositTerm, maxDepositTerm, minDepositTermType,
|
||||
maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, depositAmount, maturityAmount, maturityDate,
|
||||
depositPeriod, depositPeriodFrequency, mandatoryRecommendedDepositAmount, periodFrequencyTypeOptions, depositType,
|
||||
onAccountClosure, onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas, expectedFirstDepositOnDate,
|
||||
totalOverdueAmount, noOfOverdueInstallments, isMandatoryDeposit, allowWithdrawal, adjustAdvanceTowardsFuturePayments,
|
||||
isCalendarInherited, recurringFrequency, recurringFrequencyType, depositAccountData.withHoldTax,
|
||||
depositAccountData.taxGroup);
|
||||
}
|
||||
|
||||
public static RecurringDepositAccountData withInterestChartAndRecurringDetails(final RecurringDepositAccountData account,
|
||||
final DepositAccountInterestRateChartData accountChart, final Integer recurringFrequency,
|
||||
final EnumOptionData recurringFrequencyType) {
|
||||
return new RecurringDepositAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
||||
account.clientId, account.clientName, account.depositProductId, account.depositProductName, account.fieldOfficerId,
|
||||
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
||||
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
||||
account.interestCalculationDaysInYearType, account.minRequiredOpeningBalance, account.lockinPeriodFrequency,
|
||||
account.lockinPeriodFrequencyType, account.withdrawalFeeForTransfers, account.minBalanceForInterestCalculation,
|
||||
account.summary, account.transactions, account.productOptions, account.fieldOfficerOptions,
|
||||
account.interestCompoundingPeriodTypeOptions, account.interestPostingPeriodTypeOptions,
|
||||
account.interestCalculationTypeOptions, account.interestCalculationDaysInYearTypeOptions,
|
||||
account.lockinPeriodFrequencyTypeOptions, account.withdrawalFeeTypeOptions, account.charges, account.chargeOptions,
|
||||
accountChart, account.chartTemplate, account.preClosurePenalApplicable, account.preClosurePenalInterest,
|
||||
account.preClosurePenalInterestOnType, account.preClosurePenalInterestOnTypeOptions, account.minDepositTerm,
|
||||
account.maxDepositTerm, account.minDepositTermType, account.maxDepositTermType, account.inMultiplesOfDepositTerm,
|
||||
account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount, account.maturityDate,
|
||||
account.depositPeriod, account.depositPeriodFrequency, account.mandatoryRecommendedDepositAmount,
|
||||
account.periodFrequencyTypeOptions, account.depositType, account.onAccountClosure, account.onAccountClosureOptions,
|
||||
account.paymentTypeOptions, account.savingsAccounts, account.expectedFirstDepositOnDate, account.totalOverdueAmount,
|
||||
account.noOfOverdueInstallments, account.isMandatoryDeposit, account.allowWithdrawal,
|
||||
account.adjustAdvanceTowardsFuturePayments, account.isCalendarInherited, recurringFrequency, recurringFrequencyType,
|
||||
account.withHoldTax, account.taxGroup);
|
||||
}
|
||||
|
||||
public static RecurringDepositAccountData withTemplateOptions(final RecurringDepositAccountData account,
|
||||
final RecurringDepositAccountData template, final Collection<SavingsAccountTransactionData> transactions,
|
||||
final Collection<SavingsAccountChargeData> charges) {
|
||||
|
||||
if (template == null) {
|
||||
final Collection<DepositProductData> productOptions = null;
|
||||
final Collection<StaffData> fieldOfficerOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null;
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions = null;
|
||||
|
||||
return withTemplateOptions(account, productOptions, fieldOfficerOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, transactions, charges, chargeOptions,
|
||||
preClosurePenalInterestOnTypeOptions, periodFrequencyTypeOptions);
|
||||
}
|
||||
|
||||
return new RecurringDepositAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
||||
account.clientId, account.clientName, account.depositProductId, account.depositProductName, account.fieldOfficerId,
|
||||
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
||||
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
||||
account.interestCalculationDaysInYearType, account.minRequiredOpeningBalance, account.lockinPeriodFrequency,
|
||||
account.lockinPeriodFrequencyType, account.withdrawalFeeForTransfers, account.minBalanceForInterestCalculation,
|
||||
account.summary, transactions, template.productOptions, template.fieldOfficerOptions,
|
||||
template.interestCompoundingPeriodTypeOptions, template.interestPostingPeriodTypeOptions,
|
||||
template.interestCalculationTypeOptions, template.interestCalculationDaysInYearTypeOptions,
|
||||
template.lockinPeriodFrequencyTypeOptions, template.withdrawalFeeTypeOptions, charges, template.chargeOptions,
|
||||
account.accountChart, account.chartTemplate, account.preClosurePenalApplicable, account.preClosurePenalInterest,
|
||||
account.preClosurePenalInterestOnType, template.preClosurePenalInterestOnTypeOptions, account.minDepositTerm,
|
||||
account.maxDepositTerm, account.minDepositTermType, account.maxDepositTermType, account.inMultiplesOfDepositTerm,
|
||||
account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount, account.maturityDate,
|
||||
account.depositPeriod, account.depositPeriodFrequency, account.mandatoryRecommendedDepositAmount,
|
||||
template.periodFrequencyTypeOptions, account.depositType, account.onAccountClosure, account.onAccountClosureOptions,
|
||||
account.paymentTypeOptions, account.savingsAccounts, account.expectedFirstDepositOnDate, account.totalOverdueAmount,
|
||||
account.noOfOverdueInstallments, account.isMandatoryDeposit, account.allowWithdrawal,
|
||||
account.adjustAdvanceTowardsFuturePayments, account.isCalendarInherited, account.recurringFrequency,
|
||||
account.recurringFrequencyType, account.withHoldTax, account.taxGroup);
|
||||
|
||||
}
|
||||
|
||||
public static RecurringDepositAccountData withTemplateOptions(final RecurringDepositAccountData account,
|
||||
final Collection<DepositProductData> productOptions, final Collection<StaffData> fieldOfficerOptions,
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<SavingsAccountTransactionData> transactions, final Collection<SavingsAccountChargeData> charges,
|
||||
final Collection<ChargeData> chargeOptions, final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions,
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions) {
|
||||
|
||||
return new RecurringDepositAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
||||
account.clientId, account.clientName, account.depositProductId, account.depositProductName, account.fieldOfficerId,
|
||||
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
||||
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
||||
account.interestCalculationDaysInYearType, account.minRequiredOpeningBalance, account.lockinPeriodFrequency,
|
||||
account.lockinPeriodFrequencyType, account.withdrawalFeeForTransfers, account.minBalanceForInterestCalculation,
|
||||
account.summary, transactions, productOptions, fieldOfficerOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, charges, chargeOptions, account.accountChart,
|
||||
account.chartTemplate, account.preClosurePenalApplicable, account.preClosurePenalInterest,
|
||||
account.preClosurePenalInterestOnType, preClosurePenalInterestOnTypeOptions, account.minDepositTerm, account.maxDepositTerm,
|
||||
account.minDepositTermType, account.maxDepositTermType, account.inMultiplesOfDepositTerm,
|
||||
account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount, account.maturityDate,
|
||||
account.depositPeriod, account.depositPeriodFrequency, account.mandatoryRecommendedDepositAmount,
|
||||
periodFrequencyTypeOptions, account.depositType, account.onAccountClosure, account.onAccountClosureOptions,
|
||||
account.paymentTypeOptions, account.savingsAccounts, account.expectedFirstDepositOnDate, account.totalOverdueAmount,
|
||||
account.noOfOverdueInstallments, account.isMandatoryDeposit, account.allowWithdrawal,
|
||||
account.adjustAdvanceTowardsFuturePayments, account.isCalendarInherited, account.recurringFrequency,
|
||||
account.recurringFrequencyType, account.withHoldTax, account.taxGroup);
|
||||
}
|
||||
|
||||
public static RecurringDepositAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId,
|
||||
final String groupName) {
|
||||
|
||||
final Long id = null;
|
||||
final String accountNo = null;
|
||||
final String externalId = null;
|
||||
final Long productId = null;
|
||||
final String productName = null;
|
||||
final Long fieldOfficerId = null;
|
||||
final String fieldOfficerName = null;
|
||||
final SavingsAccountStatusEnumData status = null;
|
||||
final SavingsAccountApplicationTimelineData timeline = null;
|
||||
final CurrencyData currency = null;
|
||||
final BigDecimal nominalAnnualInterestRate = null;
|
||||
final EnumOptionData interestPeriodType = null;
|
||||
final EnumOptionData interestPostingPeriodType = null;
|
||||
final EnumOptionData interestCalculationType = null;
|
||||
final EnumOptionData interestCalculationDaysInYearType = null;
|
||||
final BigDecimal minRequiredOpeningBalance = null;
|
||||
final Integer lockinPeriodFrequency = null;
|
||||
final EnumOptionData lockinPeriodFrequencyType = null;
|
||||
final boolean withdrawalFeeForTransfers = false;
|
||||
final BigDecimal minBalanceForInterestCalculation = null;
|
||||
final SavingsAccountSummaryData summary = null;
|
||||
final Collection<SavingsAccountTransactionData> transactions = null;
|
||||
|
||||
final Collection<DepositProductData> productOptions = null;
|
||||
final Collection<StaffData> fieldOfficerOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
|
||||
final Collection<SavingsAccountChargeData> charges = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
|
||||
final DepositAccountInterestRateChartData accountChart = null;
|
||||
final DepositAccountInterestRateChartData chartTemplate = null;
|
||||
final boolean preClosurePenalApplicable = false;
|
||||
final BigDecimal preClosurePenalInterest = null;
|
||||
final EnumOptionData preClosurePenalInterestOnType = null;
|
||||
final Integer minDepositTerm = null;
|
||||
final Integer maxDepositTerm = null;
|
||||
final EnumOptionData minDepositTermType = null;
|
||||
final EnumOptionData maxDepositTermType = null;
|
||||
final Integer inMultiplesOfDepositTerm = null;
|
||||
final EnumOptionData inMultiplesOfDepositTermType = null;
|
||||
final BigDecimal depositAmount = null;
|
||||
final BigDecimal maturityAmount = null;
|
||||
final LocalDate maturityDate = null;
|
||||
final Integer depositPeriod = null;
|
||||
final EnumOptionData depositPeriodFrequency = null;
|
||||
final BigDecimal mandatoryRecommendedDepositAmount = null;
|
||||
final EnumOptionData onAccountClosure = null;
|
||||
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null;
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions = null;
|
||||
|
||||
final EnumOptionData depositType = SavingsEnumerations.depositType(DepositAccountType.RECURRING_DEPOSIT.getValue());
|
||||
final Collection<EnumOptionData> onAccountClosureOptions = null;
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = null;
|
||||
final Collection<SavingsAccountData> savingsAccountDatas = null;
|
||||
final LocalDate expectedFirstDepositOnDate = null;
|
||||
|
||||
final BigDecimal totalOverdueAmount = null;
|
||||
final Integer noOfOverdueInstallments = null;
|
||||
final boolean isMandatoryDeposit = false;
|
||||
final boolean allowWithdrawal = false;
|
||||
final boolean adjustAdvanceTowardsFuturePayments = false;
|
||||
|
||||
final boolean isCalendarInherited = false;
|
||||
final Integer recurringFrequency = null;
|
||||
final EnumOptionData recurringFrequencyType = null;
|
||||
final boolean withHoldTax = false;
|
||||
final TaxGroupData taxGroup = null;
|
||||
|
||||
return new RecurringDepositAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
|
||||
fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate, interestPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, minBalanceForInterestCalculation, summary,
|
||||
transactions, productOptions, fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, charges, chargeOptions, accountChart, chartTemplate, preClosurePenalApplicable,
|
||||
preClosurePenalInterest, preClosurePenalInterestOnType, preClosurePenalInterestOnTypeOptions, minDepositTerm,
|
||||
maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType,
|
||||
depositAmount, maturityAmount, maturityDate, depositPeriod, depositPeriodFrequency, mandatoryRecommendedDepositAmount,
|
||||
periodFrequencyTypeOptions, depositType, onAccountClosure, onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas,
|
||||
expectedFirstDepositOnDate, totalOverdueAmount, noOfOverdueInstallments, isMandatoryDeposit, allowWithdrawal,
|
||||
adjustAdvanceTowardsFuturePayments, isCalendarInherited, recurringFrequency, recurringFrequencyType, withHoldTax, taxGroup);
|
||||
}
|
||||
|
||||
public static RecurringDepositAccountData preClosureDetails(final Long accountId, final BigDecimal maturityAmount,
|
||||
final Collection<EnumOptionData> onAccountClosureOptions, final Collection<PaymentTypeData> paymentTypeOptions,
|
||||
final Collection<SavingsAccountData> savingsAccountDatas) {
|
||||
|
||||
final String accountNo = null;
|
||||
final String externalId = null;
|
||||
final Long productId = null;
|
||||
final String productName = null;
|
||||
final Long fieldOfficerId = null;
|
||||
final String fieldOfficerName = null;
|
||||
final SavingsAccountStatusEnumData status = null;
|
||||
final SavingsAccountApplicationTimelineData timeline = null;
|
||||
final CurrencyData currency = null;
|
||||
final BigDecimal nominalAnnualInterestRate = null;
|
||||
final EnumOptionData interestPeriodType = null;
|
||||
final EnumOptionData interestPostingPeriodType = null;
|
||||
final EnumOptionData interestCalculationType = null;
|
||||
final EnumOptionData interestCalculationDaysInYearType = null;
|
||||
final BigDecimal minRequiredOpeningBalance = null;
|
||||
final Integer lockinPeriodFrequency = null;
|
||||
final EnumOptionData lockinPeriodFrequencyType = null;
|
||||
final boolean withdrawalFeeForTransfers = false;
|
||||
final BigDecimal minBalanceForInterestCalculation = null;
|
||||
final SavingsAccountSummaryData summary = null;
|
||||
final Collection<SavingsAccountTransactionData> transactions = null;
|
||||
|
||||
final Collection<DepositProductData> productOptions = null;
|
||||
final Collection<StaffData> fieldOfficerOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
|
||||
final Collection<SavingsAccountChargeData> charges = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
|
||||
final DepositAccountInterestRateChartData accountChart = null;
|
||||
final DepositAccountInterestRateChartData chartTemplate = null;
|
||||
final boolean preClosurePenalApplicable = false;
|
||||
final BigDecimal preClosurePenalInterest = null;
|
||||
final EnumOptionData preClosurePenalInterestOnType = null;
|
||||
final Integer minDepositTerm = null;
|
||||
final Integer maxDepositTerm = null;
|
||||
final EnumOptionData minDepositTermType = null;
|
||||
final EnumOptionData maxDepositTermType = null;
|
||||
final Integer inMultiplesOfDepositTerm = null;
|
||||
final EnumOptionData inMultiplesOfDepositTermType = null;
|
||||
final BigDecimal depositAmount = null;
|
||||
final LocalDate maturityDate = null;
|
||||
final Integer depositPeriod = null;
|
||||
final EnumOptionData depositPeriodFrequency = null;
|
||||
final BigDecimal mandatoryRecommendedDepositAmount = null;
|
||||
final EnumOptionData onAccountClosure = null;
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null;
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions = null;
|
||||
final EnumOptionData depositType = SavingsEnumerations.depositType(DepositAccountType.RECURRING_DEPOSIT.getValue());
|
||||
|
||||
final Long groupId = null;
|
||||
final String groupName = null;
|
||||
final Long clientId = null;
|
||||
final String clientName = null;
|
||||
final LocalDate expectedFirstDepositOnDate = null;
|
||||
|
||||
final BigDecimal totalOverdueAmount = null;
|
||||
final Integer noOfOverdueInstallments = null;
|
||||
final boolean isMandatoryDeposit = false;
|
||||
final boolean allowWithdrawal = false;
|
||||
final boolean adjustAdvanceTowardsFuturePayments = false;
|
||||
final boolean isCalendarInherited = false;
|
||||
final Integer recurringFrequency = null;
|
||||
final EnumOptionData recurringFrequencyType = null;
|
||||
final boolean withHoldTax = false;
|
||||
final TaxGroupData taxGroup = null;
|
||||
|
||||
return new RecurringDepositAccountData(accountId, accountNo, externalId, groupId, groupName, clientId, clientName, productId,
|
||||
productName, fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate, interestPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, minBalanceForInterestCalculation, summary,
|
||||
transactions, productOptions, fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, charges, chargeOptions, accountChart, chartTemplate, preClosurePenalApplicable,
|
||||
preClosurePenalInterest, preClosurePenalInterestOnType, preClosurePenalInterestOnTypeOptions, minDepositTerm,
|
||||
maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType,
|
||||
depositAmount, maturityAmount, maturityDate, depositPeriod, depositPeriodFrequency, mandatoryRecommendedDepositAmount,
|
||||
periodFrequencyTypeOptions, depositType, onAccountClosure, onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas,
|
||||
expectedFirstDepositOnDate, totalOverdueAmount, noOfOverdueInstallments, isMandatoryDeposit, allowWithdrawal,
|
||||
adjustAdvanceTowardsFuturePayments, isCalendarInherited, recurringFrequency, recurringFrequencyType, withHoldTax, taxGroup);
|
||||
}
|
||||
|
||||
public static RecurringDepositAccountData withClosureTemplateDetails(final RecurringDepositAccountData account,
|
||||
final Collection<EnumOptionData> onAccountClosureOptions, final Collection<PaymentTypeData> paymentTypeOptions,
|
||||
final Collection<SavingsAccountData> savingsAccountDatas) {
|
||||
|
||||
return new RecurringDepositAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
||||
account.clientId, account.clientName, account.depositProductId, account.depositProductName, account.fieldOfficerId,
|
||||
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
||||
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
||||
account.interestCalculationDaysInYearType, account.minRequiredOpeningBalance, account.lockinPeriodFrequency,
|
||||
account.lockinPeriodFrequencyType, account.withdrawalFeeForTransfers, account.minBalanceForInterestCalculation,
|
||||
account.summary, account.transactions, account.productOptions, account.fieldOfficerOptions,
|
||||
account.interestCompoundingPeriodTypeOptions, account.interestPostingPeriodTypeOptions,
|
||||
account.interestCalculationTypeOptions, account.interestCalculationDaysInYearTypeOptions,
|
||||
account.lockinPeriodFrequencyTypeOptions, account.withdrawalFeeTypeOptions, account.charges, account.chargeOptions,
|
||||
account.accountChart, account.chartTemplate, account.preClosurePenalApplicable, account.preClosurePenalInterest,
|
||||
account.preClosurePenalInterestOnType, account.preClosurePenalInterestOnTypeOptions, account.minDepositTerm,
|
||||
account.maxDepositTerm, account.minDepositTermType, account.maxDepositTermType, account.inMultiplesOfDepositTerm,
|
||||
account.inMultiplesOfDepositTermType, account.depositAmount, account.maturityAmount, account.maturityDate,
|
||||
account.depositPeriod, account.depositPeriodFrequency, account.mandatoryRecommendedDepositAmount,
|
||||
account.periodFrequencyTypeOptions, account.depositType, account.onAccountClosure, onAccountClosureOptions,
|
||||
paymentTypeOptions, savingsAccountDatas, account.expectedFirstDepositOnDate, account.totalOverdueAmount,
|
||||
account.noOfOverdueInstallments, account.isMandatoryDeposit, account.allowWithdrawal,
|
||||
account.adjustAdvanceTowardsFuturePayments, account.isCalendarInherited, account.recurringFrequency,
|
||||
account.recurringFrequencyType, account.withHoldTax, account.taxGroup);
|
||||
}
|
||||
|
||||
private RecurringDepositAccountData(final Long id, final String accountNo, final String externalId, final Long groupId,
|
||||
final String groupName, final Long clientId, final String clientName, final Long productId, final String productName,
|
||||
final Long fieldofficerId, final String fieldofficerName, final SavingsAccountStatusEnumData status,
|
||||
final SavingsAccountApplicationTimelineData timeline, final CurrencyData currency, final BigDecimal nominalAnnualInterestRate,
|
||||
final EnumOptionData interestPeriodType, final EnumOptionData interestPostingPeriodType,
|
||||
final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType,
|
||||
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType,
|
||||
final boolean withdrawalFeeForTransfers, final BigDecimal minBalanceForInterestCalculation,
|
||||
final SavingsAccountSummaryData summary, final Collection<SavingsAccountTransactionData> transactions,
|
||||
final Collection<DepositProductData> productOptions, final Collection<StaffData> fieldOfficerOptions,
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<SavingsAccountChargeData> charges, final Collection<ChargeData> chargeOptions,
|
||||
final DepositAccountInterestRateChartData accountChart, final DepositAccountInterestRateChartData chartTemplate,
|
||||
final boolean preClosurePenalApplicable, final BigDecimal preClosurePenalInterest,
|
||||
final EnumOptionData preClosurePenalInterestOnType, final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions,
|
||||
final Integer minDepositTerm, final Integer maxDepositTerm, final EnumOptionData minDepositTermType,
|
||||
final EnumOptionData maxDepositTermType, final Integer inMultiplesOfDepositTerm,
|
||||
final EnumOptionData inMultiplesOfDepositTermType, final BigDecimal depositAmount, final BigDecimal maturityAmount,
|
||||
final LocalDate maturityDate, final Integer depositPeriod, final EnumOptionData depositPeriodFrequency,
|
||||
final BigDecimal mandatoryRecommendedDepositAmount, final Collection<EnumOptionData> periodFrequencyTypeOptions,
|
||||
final EnumOptionData depositType, final EnumOptionData onAccountClosure,
|
||||
final Collection<EnumOptionData> onAccountClosureOptions, final Collection<PaymentTypeData> paymentTypeOptions,
|
||||
final Collection<SavingsAccountData> savingsAccountDatas, final LocalDate expectedFirstDepositOnDate,
|
||||
final BigDecimal totalOverdueAmount, final Integer noOfOverdueInstallments, final boolean isMandatoryDeposit,
|
||||
final boolean allowWithdrawal, final boolean adjustAdvanceTowardsFuturePayments, final boolean isCalendarInherited,
|
||||
final Integer recurringFrequency, final EnumOptionData recurringFrequencyType, final boolean withHoldTax,
|
||||
final TaxGroupData taxGroup) {
|
||||
|
||||
super(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName, fieldofficerId, fieldofficerName,
|
||||
status, timeline, currency, nominalAnnualInterestRate, interestPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary, transactions, productOptions, fieldOfficerOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, charges,
|
||||
chargeOptions, accountChart, chartTemplate, depositType, minBalanceForInterestCalculation, withHoldTax, taxGroup);
|
||||
|
||||
this.preClosurePenalApplicable = preClosurePenalApplicable;
|
||||
this.preClosurePenalInterest = preClosurePenalInterest;
|
||||
this.preClosurePenalInterestOnType = preClosurePenalInterestOnType;
|
||||
this.minDepositTerm = minDepositTerm;
|
||||
this.maxDepositTerm = maxDepositTerm;
|
||||
this.minDepositTermType = minDepositTermType;
|
||||
this.maxDepositTermType = maxDepositTermType;
|
||||
this.inMultiplesOfDepositTerm = inMultiplesOfDepositTerm;
|
||||
this.inMultiplesOfDepositTermType = inMultiplesOfDepositTermType;
|
||||
this.depositAmount = depositAmount;
|
||||
this.maturityAmount = maturityAmount;
|
||||
this.maturityDate = maturityDate;
|
||||
this.depositPeriod = depositPeriod;
|
||||
this.depositPeriodFrequency = depositPeriodFrequency;
|
||||
this.expectedFirstDepositOnDate = expectedFirstDepositOnDate;
|
||||
this.mandatoryRecommendedDepositAmount = mandatoryRecommendedDepositAmount;
|
||||
this.totalOverdueAmount = totalOverdueAmount;
|
||||
this.noOfOverdueInstallments = noOfOverdueInstallments;
|
||||
this.isMandatoryDeposit = isMandatoryDeposit;
|
||||
this.allowWithdrawal = allowWithdrawal;
|
||||
this.adjustAdvanceTowardsFuturePayments = adjustAdvanceTowardsFuturePayments;
|
||||
|
||||
this.isCalendarInherited = isCalendarInherited;
|
||||
this.recurringFrequency = recurringFrequency;
|
||||
this.recurringFrequencyType = recurringFrequencyType;
|
||||
|
||||
this.preClosurePenalInterestOnTypeOptions = preClosurePenalInterestOnTypeOptions;
|
||||
this.periodFrequencyTypeOptions = periodFrequencyTypeOptions;
|
||||
this.onAccountClosure = onAccountClosure;
|
||||
this.savingsAccounts = savingsAccountDatas;
|
||||
|
||||
// account close template options
|
||||
this.onAccountClosureOptions = onAccountClosureOptions;
|
||||
this.paymentTypeOptions = paymentTypeOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof RecurringDepositAccountData)) {
|
||||
return false;
|
||||
}
|
||||
final RecurringDepositAccountData rhs = (RecurringDepositAccountData) obj;
|
||||
return new EqualsBuilder().append(this.id, rhs.id).append(this.accountNo, rhs.accountNo).isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37).append(this.id).append(this.accountNo).toHashCode();
|
||||
}
|
||||
|
||||
public boolean isIsMandatoryDeposit() {
|
||||
return this.isMandatoryDeposit;
|
||||
}
|
||||
|
||||
public boolean isIsCalendarInherited() {
|
||||
return this.isCalendarInherited;
|
||||
}
|
||||
}
|
||||
+478
@@ -0,0 +1,478 @@
|
||||
/**
|
||||
* 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.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.portfolio.charge.data.ChargeData;
|
||||
import org.apache.fineract.portfolio.interestratechart.data.InterestRateChartData;
|
||||
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
|
||||
import org.apache.fineract.portfolio.tax.data.TaxGroupData;
|
||||
|
||||
/**
|
||||
* Immutable data object represent a Recurring Deposit product.
|
||||
*/
|
||||
public final class RecurringDepositProductData extends DepositProductData {
|
||||
|
||||
private boolean preClosurePenalApplicable;
|
||||
private BigDecimal preClosurePenalInterest;
|
||||
private EnumOptionData preClosurePenalInterestOnType;
|
||||
private Integer minDepositTerm;
|
||||
private Integer maxDepositTerm;
|
||||
private EnumOptionData minDepositTermType;
|
||||
private EnumOptionData maxDepositTermType;
|
||||
private Integer inMultiplesOfDepositTerm;
|
||||
private EnumOptionData inMultiplesOfDepositTermType;
|
||||
private BigDecimal minDepositAmount;
|
||||
private BigDecimal depositAmount;
|
||||
private BigDecimal maxDepositAmount;
|
||||
private boolean isMandatoryDeposit;
|
||||
private boolean allowWithdrawal;
|
||||
private boolean adjustAdvanceTowardsFuturePayments;
|
||||
|
||||
private Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions;
|
||||
private Collection<EnumOptionData> periodFrequencyTypeOptions;
|
||||
|
||||
public static RecurringDepositProductData template(final CurrencyData currency, final EnumOptionData interestCompoundingPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final EnumOptionData accountingRule,
|
||||
final Collection<CurrencyData> currencyOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<PaymentTypeData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> chargeOptions,
|
||||
final Collection<ChargeData> penaltyOptions, final InterestRateChartData chartTemplate,
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions,
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions, final Collection<TaxGroupData> taxGroupOptions) {
|
||||
|
||||
final Long id = null;
|
||||
final String name = null;
|
||||
final String shortName = null;
|
||||
final String description = null;
|
||||
final BigDecimal nominalAnnualInterestRate = null;
|
||||
|
||||
final Integer lockinPeriodFrequency = null;
|
||||
final EnumOptionData lockinPeriodFrequencyType = null;
|
||||
final BigDecimal minBalanceForInterestCalculation = null;
|
||||
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
final Collection<ChargeData> charges = null;
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings = null;
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings = null;
|
||||
final Collection<InterestRateChartData> interestRateCharts = null;
|
||||
final boolean preClosurePenalApplicable = false;
|
||||
final BigDecimal preClosurePenalInterest = null;
|
||||
final EnumOptionData preClosurePenalInterestOnType = null;
|
||||
final boolean isMandatoryDeposit = false;
|
||||
final boolean allowWithdrawal = false;
|
||||
final boolean adjustAdvanceTowardsFuturePayments = false;
|
||||
final Integer minDepositTerm = null;
|
||||
final Integer maxDepositTerm = null;
|
||||
final EnumOptionData minDepositTermType = null;
|
||||
final EnumOptionData maxDepositTermType = null;
|
||||
final Integer inMultiplesOfDepositTerm = null;
|
||||
final EnumOptionData inMultiplesOfDepositTermType = null;
|
||||
final BigDecimal minDepositAmount = null;
|
||||
final BigDecimal depositAmount = null;
|
||||
final BigDecimal maxDepositAmount = null;
|
||||
final boolean withHoldTax = false;
|
||||
final TaxGroupData taxGroup = null;
|
||||
|
||||
return new RecurringDepositProductData(id, name, shortName, description, currency, nominalAnnualInterestRate,
|
||||
interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, minBalanceForInterestCalculation, accountingRule, accountingMappings,
|
||||
paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, charges, chargeOptions,
|
||||
penaltyOptions, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, interestRateCharts, chartTemplate,
|
||||
preClosurePenalApplicable, preClosurePenalInterest, preClosurePenalInterestOnType, preClosurePenalInterestOnTypeOptions,
|
||||
minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm,
|
||||
inMultiplesOfDepositTermType, isMandatoryDeposit, allowWithdrawal, adjustAdvanceTowardsFuturePayments,
|
||||
periodFrequencyTypeOptions, minDepositAmount, depositAmount, maxDepositAmount, withHoldTax, taxGroup, taxGroupOptions);
|
||||
}
|
||||
|
||||
public static RecurringDepositProductData withCharges(final RecurringDepositProductData existingProduct,
|
||||
final Collection<ChargeData> charges) {
|
||||
return new RecurringDepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName,
|
||||
existingProduct.description, existingProduct.currency, existingProduct.nominalAnnualInterestRate,
|
||||
existingProduct.interestCompoundingPeriodType, existingProduct.interestPostingPeriodType,
|
||||
existingProduct.interestCalculationType, existingProduct.interestCalculationDaysInYearType,
|
||||
existingProduct.lockinPeriodFrequency, existingProduct.lockinPeriodFrequencyType,
|
||||
existingProduct.minBalanceForInterestCalculation, existingProduct.accountingRule, existingProduct.accountingMappings,
|
||||
existingProduct.paymentChannelToFundSourceMappings, existingProduct.currencyOptions,
|
||||
existingProduct.interestCompoundingPeriodTypeOptions, existingProduct.interestPostingPeriodTypeOptions,
|
||||
existingProduct.interestCalculationTypeOptions, existingProduct.interestCalculationDaysInYearTypeOptions,
|
||||
existingProduct.lockinPeriodFrequencyTypeOptions, existingProduct.withdrawalFeeTypeOptions,
|
||||
existingProduct.paymentTypeOptions, existingProduct.accountingRuleOptions, existingProduct.accountingMappingOptions,
|
||||
charges, existingProduct.chargeOptions, existingProduct.penaltyOptions, existingProduct.feeToIncomeAccountMappings,
|
||||
existingProduct.penaltyToIncomeAccountMappings, existingProduct.interestRateCharts, existingProduct.chartTemplate,
|
||||
existingProduct.preClosurePenalApplicable, existingProduct.preClosurePenalInterest,
|
||||
existingProduct.preClosurePenalInterestOnType, existingProduct.preClosurePenalInterestOnTypeOptions,
|
||||
existingProduct.minDepositTerm, existingProduct.maxDepositTerm, existingProduct.minDepositTermType,
|
||||
existingProduct.maxDepositTermType, existingProduct.inMultiplesOfDepositTerm, existingProduct.inMultiplesOfDepositTermType,
|
||||
existingProduct.isMandatoryDeposit, existingProduct.allowWithdrawal, existingProduct.adjustAdvanceTowardsFuturePayments,
|
||||
existingProduct.periodFrequencyTypeOptions, existingProduct.minDepositAmount, existingProduct.depositAmount,
|
||||
existingProduct.maxDepositAmount, existingProduct.withHoldTax, existingProduct.taxGroup, existingProduct.taxGroupOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link RecurringDepositProductData} that contains and exist {@link RecurringDepositProductData} data
|
||||
* with further template data for dropdowns.
|
||||
*
|
||||
* @param taxGroupOptions
|
||||
* TODO
|
||||
*/
|
||||
public static RecurringDepositProductData withTemplate(final RecurringDepositProductData existingProduct,
|
||||
final Collection<CurrencyData> currencyOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<PaymentTypeData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> chargeOptions,
|
||||
final Collection<ChargeData> penaltyOptions, final InterestRateChartData chartTemplate,
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions,
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions, final Collection<TaxGroupData> taxGroupOptions) {
|
||||
|
||||
return new RecurringDepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName,
|
||||
existingProduct.description, existingProduct.currency, existingProduct.nominalAnnualInterestRate,
|
||||
existingProduct.interestCompoundingPeriodType, existingProduct.interestPostingPeriodType,
|
||||
existingProduct.interestCalculationType, existingProduct.interestCalculationDaysInYearType,
|
||||
existingProduct.lockinPeriodFrequency, existingProduct.lockinPeriodFrequencyType,
|
||||
existingProduct.minBalanceForInterestCalculation, existingProduct.accountingRule, existingProduct.accountingMappings,
|
||||
existingProduct.paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
|
||||
accountingMappingOptions, existingProduct.charges, chargeOptions, penaltyOptions,
|
||||
existingProduct.feeToIncomeAccountMappings, existingProduct.penaltyToIncomeAccountMappings,
|
||||
existingProduct.interestRateCharts, chartTemplate, existingProduct.preClosurePenalApplicable,
|
||||
existingProduct.preClosurePenalInterest, existingProduct.preClosurePenalInterestOnType,
|
||||
preClosurePenalInterestOnTypeOptions, existingProduct.minDepositTerm, existingProduct.maxDepositTerm,
|
||||
existingProduct.minDepositTermType, existingProduct.maxDepositTermType, existingProduct.inMultiplesOfDepositTerm,
|
||||
existingProduct.inMultiplesOfDepositTermType, existingProduct.isMandatoryDeposit, existingProduct.allowWithdrawal,
|
||||
existingProduct.adjustAdvanceTowardsFuturePayments, periodFrequencyTypeOptions, existingProduct.minDepositAmount,
|
||||
existingProduct.depositAmount, existingProduct.maxDepositAmount, existingProduct.withHoldTax, existingProduct.taxGroup,
|
||||
taxGroupOptions);
|
||||
|
||||
}
|
||||
|
||||
public static RecurringDepositProductData withAccountingDetails(final RecurringDepositProductData existingProduct,
|
||||
final Map<String, Object> accountingMappings, final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings,
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings,
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings) {
|
||||
|
||||
final Collection<CurrencyData> currencyOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = null;
|
||||
final Collection<EnumOptionData> accountingRuleOptions = null;
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final Collection<ChargeData> penaltyOptions = null;
|
||||
|
||||
return new RecurringDepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName,
|
||||
existingProduct.description, existingProduct.currency, existingProduct.nominalAnnualInterestRate,
|
||||
existingProduct.interestCompoundingPeriodType, existingProduct.interestPostingPeriodType,
|
||||
existingProduct.interestCalculationType, existingProduct.interestCalculationDaysInYearType,
|
||||
existingProduct.lockinPeriodFrequency, existingProduct.lockinPeriodFrequencyType,
|
||||
existingProduct.minBalanceForInterestCalculation, existingProduct.accountingRule, accountingMappings,
|
||||
paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, existingProduct.charges,
|
||||
chargeOptions, penaltyOptions, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings,
|
||||
existingProduct.interestRateCharts, existingProduct.chartTemplate, existingProduct.preClosurePenalApplicable,
|
||||
existingProduct.preClosurePenalInterest, existingProduct.preClosurePenalInterestOnType,
|
||||
existingProduct.preClosurePenalInterestOnTypeOptions, existingProduct.minDepositTerm, existingProduct.maxDepositTerm,
|
||||
existingProduct.minDepositTermType, existingProduct.maxDepositTermType, existingProduct.inMultiplesOfDepositTerm,
|
||||
existingProduct.inMultiplesOfDepositTermType, existingProduct.isMandatoryDeposit, existingProduct.allowWithdrawal,
|
||||
existingProduct.adjustAdvanceTowardsFuturePayments, existingProduct.periodFrequencyTypeOptions,
|
||||
existingProduct.minDepositAmount, existingProduct.depositAmount, existingProduct.maxDepositAmount,
|
||||
existingProduct.withHoldTax, existingProduct.taxGroup, existingProduct.taxGroupOptions);
|
||||
}
|
||||
|
||||
public static RecurringDepositProductData instance(final DepositProductData depositProductData, final boolean preClosurePenalApplicable,
|
||||
final BigDecimal preClosurePenalInterest, final EnumOptionData preClosurePenalInterestOnType, final Integer minDepositTerm,
|
||||
final Integer maxDepositTerm, final EnumOptionData minDepositTermType, final EnumOptionData maxDepositTermType,
|
||||
final Integer inMultiplesOfDepositTerm, final EnumOptionData inMultiplesOfDepositTermType, final boolean isMandatoryDeposit,
|
||||
boolean allowWithdrawal, boolean adjustAdvanceTowardsFuturePayments, final BigDecimal minDepositAmount,
|
||||
final BigDecimal depositAmount, final BigDecimal maxDepositAmount) {
|
||||
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
|
||||
final Collection<CurrencyData> currencyOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = null;
|
||||
final Collection<EnumOptionData> accountingRuleOptions = null;
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final Collection<ChargeData> penaltyOptions = null;
|
||||
final Collection<ChargeData> charges = null;
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings = null;
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings = null;
|
||||
final Collection<InterestRateChartData> interestRateCharts = null;
|
||||
final InterestRateChartData chartTemplate = null;
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null;
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions = null;
|
||||
final Collection<TaxGroupData> taxGroupOptions = null;
|
||||
|
||||
return new RecurringDepositProductData(depositProductData.id, depositProductData.name, depositProductData.shortName,
|
||||
depositProductData.description, depositProductData.currency, depositProductData.nominalAnnualInterestRate,
|
||||
depositProductData.interestCompoundingPeriodType, depositProductData.interestPostingPeriodType,
|
||||
depositProductData.interestCalculationType, depositProductData.interestCalculationDaysInYearType,
|
||||
depositProductData.lockinPeriodFrequency, depositProductData.lockinPeriodFrequencyType,
|
||||
depositProductData.minBalanceForInterestCalculation, depositProductData.accountingRule, accountingMappings,
|
||||
paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, charges, chargeOptions,
|
||||
penaltyOptions, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, interestRateCharts, chartTemplate,
|
||||
preClosurePenalApplicable, preClosurePenalInterest, preClosurePenalInterestOnType, preClosurePenalInterestOnTypeOptions,
|
||||
minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm,
|
||||
inMultiplesOfDepositTermType, isMandatoryDeposit, allowWithdrawal, adjustAdvanceTowardsFuturePayments,
|
||||
periodFrequencyTypeOptions, minDepositAmount, depositAmount, maxDepositAmount, depositProductData.withHoldTax,
|
||||
depositProductData.taxGroup, taxGroupOptions);
|
||||
}
|
||||
|
||||
public static RecurringDepositProductData lookup(final Long id, final String name) {
|
||||
|
||||
final String shortName = null;
|
||||
final CurrencyData currency = null;
|
||||
final String description = null;
|
||||
final BigDecimal nominalAnnualInterestRate = null;
|
||||
final EnumOptionData interestCompoundingPeriodType = null;
|
||||
final EnumOptionData interestPostingPeriodType = null;
|
||||
final EnumOptionData interestCalculationType = null;
|
||||
final EnumOptionData interestCalculationDaysInYearType = null;
|
||||
|
||||
final Integer lockinPeriodFrequency = null;
|
||||
final EnumOptionData lockinPeriodFrequencyType = null;
|
||||
final BigDecimal minBalanceForInterestCalculation = null;
|
||||
|
||||
final EnumOptionData accountingType = null;
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
|
||||
final Collection<CurrencyData> currencyOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = null;
|
||||
final Collection<EnumOptionData> accountingRuleOptions = null;
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions = null;
|
||||
final Collection<ChargeData> charges = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final Collection<ChargeData> penaltyOptions = null;
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings = null;
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings = null;
|
||||
final Collection<InterestRateChartData> interestRateCharts = null;
|
||||
final InterestRateChartData chartTemplate = null;
|
||||
final boolean preClosurePenalApplicable = false;
|
||||
final BigDecimal preClosurePenalInterest = null;
|
||||
final EnumOptionData preClosurePenalInterestOnType = null;
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null;
|
||||
final boolean isMandatoryDeposit = false;
|
||||
final boolean allowWithdrawal = false;
|
||||
final boolean adjustAdvanceTowardsFuturePayments = false;
|
||||
final Integer minDepositTerm = null;
|
||||
final Integer maxDepositTerm = null;
|
||||
final EnumOptionData minDepositTermType = null;
|
||||
final EnumOptionData maxDepositTermType = null;
|
||||
final Integer inMultiplesOfDepositTerm = null;
|
||||
final EnumOptionData inMultiplesOfDepositTermType = null;
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions = null;
|
||||
final BigDecimal minDepositAmount = null;
|
||||
final BigDecimal depositAmount = null;
|
||||
final BigDecimal maxDepositAmount = null;
|
||||
final boolean withHoldTax = false;
|
||||
final TaxGroupData taxGroup = null;
|
||||
final Collection<TaxGroupData> taxGroupOptions = null;
|
||||
|
||||
return new RecurringDepositProductData(id, name, shortName, description, currency, nominalAnnualInterestRate,
|
||||
interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, minBalanceForInterestCalculation, accountingType, accountingMappings,
|
||||
paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, charges, chargeOptions,
|
||||
penaltyOptions, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, interestRateCharts, chartTemplate,
|
||||
preClosurePenalApplicable, preClosurePenalInterest, preClosurePenalInterestOnType, preClosurePenalInterestOnTypeOptions,
|
||||
minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm,
|
||||
inMultiplesOfDepositTermType, isMandatoryDeposit, allowWithdrawal, adjustAdvanceTowardsFuturePayments,
|
||||
periodFrequencyTypeOptions, minDepositAmount, depositAmount, maxDepositAmount, withHoldTax, taxGroup, taxGroupOptions);
|
||||
}
|
||||
|
||||
public static RecurringDepositProductData withInterestChart(final RecurringDepositProductData product,
|
||||
final Collection<InterestRateChartData> interestRateCharts) {
|
||||
return new RecurringDepositProductData(product.id, product.name, product.shortName, product.description, product.currency,
|
||||
product.nominalAnnualInterestRate, product.interestCompoundingPeriodType, product.interestPostingPeriodType,
|
||||
product.interestCalculationType, product.interestCalculationDaysInYearType, product.lockinPeriodFrequency,
|
||||
product.lockinPeriodFrequencyType, product.minBalanceForInterestCalculation, product.accountingRule,
|
||||
product.accountingMappings, product.paymentChannelToFundSourceMappings, product.currencyOptions,
|
||||
product.interestCompoundingPeriodTypeOptions, product.interestPostingPeriodTypeOptions,
|
||||
product.interestCalculationTypeOptions, product.interestCalculationDaysInYearTypeOptions,
|
||||
product.lockinPeriodFrequencyTypeOptions, product.withdrawalFeeTypeOptions, product.paymentTypeOptions,
|
||||
product.accountingRuleOptions, product.accountingMappingOptions, product.charges, product.chargeOptions,
|
||||
product.penaltyOptions, product.feeToIncomeAccountMappings, product.penaltyToIncomeAccountMappings, interestRateCharts,
|
||||
product.chartTemplate, product.preClosurePenalApplicable, product.preClosurePenalInterest,
|
||||
product.preClosurePenalInterestOnType, product.preClosurePenalInterestOnTypeOptions, product.minDepositTerm,
|
||||
product.maxDepositTerm, product.minDepositTermType, product.maxDepositTermType, product.inMultiplesOfDepositTerm,
|
||||
product.inMultiplesOfDepositTermType, product.isMandatoryDeposit, product.allowWithdrawal,
|
||||
product.adjustAdvanceTowardsFuturePayments, product.periodFrequencyTypeOptions, product.minDepositAmount,
|
||||
product.depositAmount, product.maxDepositAmount, product.withHoldTax, product.taxGroup, product.taxGroupOptions);
|
||||
|
||||
}
|
||||
|
||||
private RecurringDepositProductData(final Long id, final String name, final String shortName, final String description,
|
||||
final CurrencyData currency, final BigDecimal nominalAnnualInterestRate, final EnumOptionData interestCompoundingPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final Integer lockinPeriodFrequency,
|
||||
final EnumOptionData lockinPeriodFrequencyType, final BigDecimal minBalanceForInterestCalculation,
|
||||
final EnumOptionData accountingType, final Map<String, Object> accountingMappings,
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings,
|
||||
final Collection<CurrencyData> currencyOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<PaymentTypeData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> charges,
|
||||
final Collection<ChargeData> chargeOptions, final Collection<ChargeData> penaltyOptions,
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings,
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings,
|
||||
final Collection<InterestRateChartData> interestRateCharts, final InterestRateChartData chartTemplate,
|
||||
final boolean preClosurePenalApplicable, final BigDecimal preClosurePenalInterest,
|
||||
final EnumOptionData preClosurePenalInterestOnType, final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions,
|
||||
final Integer minDepositTerm, final Integer maxDepositTerm, final EnumOptionData minDepositTermType,
|
||||
final EnumOptionData maxDepositTermType, final Integer inMultiplesOfDepositTerm,
|
||||
final EnumOptionData inMultiplesOfDepositTermType, final boolean isMandatoryDeposit, boolean allowWithdrawal,
|
||||
boolean adjustAdvanceTowardsFuturePayments, final Collection<EnumOptionData> periodFrequencyTypeOptions,
|
||||
final BigDecimal minDepositAmount, final BigDecimal depositAmount, final BigDecimal maxDepositAmount, final boolean withHoldTax,
|
||||
final TaxGroupData taxGroup, final Collection<TaxGroupData> taxGroupOptions) {
|
||||
|
||||
super(id, name, shortName, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, accountingType, accountingMappings, paymentChannelToFundSourceMappings, currencyOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions,
|
||||
accountingRuleOptions, accountingMappingOptions, charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
|
||||
penaltyToIncomeAccountMappings, interestRateCharts, chartTemplate, minBalanceForInterestCalculation, withHoldTax, taxGroup,
|
||||
taxGroupOptions);
|
||||
|
||||
this.preClosurePenalApplicable = preClosurePenalApplicable;
|
||||
this.preClosurePenalInterest = preClosurePenalInterest;
|
||||
this.preClosurePenalInterestOnType = preClosurePenalInterestOnType;
|
||||
this.minDepositTerm = minDepositTerm;
|
||||
this.maxDepositTerm = maxDepositTerm;
|
||||
this.minDepositTermType = minDepositTermType;
|
||||
this.maxDepositTermType = maxDepositTermType;
|
||||
this.inMultiplesOfDepositTerm = inMultiplesOfDepositTerm;
|
||||
this.inMultiplesOfDepositTermType = inMultiplesOfDepositTermType;
|
||||
this.minDepositAmount = minDepositAmount;
|
||||
this.depositAmount = depositAmount;
|
||||
this.maxDepositAmount = maxDepositAmount;
|
||||
this.isMandatoryDeposit = isMandatoryDeposit;
|
||||
this.allowWithdrawal = allowWithdrawal;
|
||||
this.adjustAdvanceTowardsFuturePayments = adjustAdvanceTowardsFuturePayments;
|
||||
|
||||
// template data
|
||||
this.preClosurePenalInterestOnTypeOptions = preClosurePenalInterestOnTypeOptions;
|
||||
this.periodFrequencyTypeOptions = periodFrequencyTypeOptions;
|
||||
}
|
||||
|
||||
public EnumOptionData getMinDepositTermType() {
|
||||
return minDepositTermType;
|
||||
}
|
||||
|
||||
public boolean isPreClosurePenalApplicable() {
|
||||
return preClosurePenalApplicable;
|
||||
}
|
||||
|
||||
public BigDecimal getPreClosurePenalInterest() {
|
||||
return preClosurePenalInterest;
|
||||
}
|
||||
|
||||
public EnumOptionData getPreClosurePenalInterestOnType() {
|
||||
return preClosurePenalInterestOnType;
|
||||
}
|
||||
|
||||
public Integer getMinDepositTerm() {
|
||||
return minDepositTerm;
|
||||
}
|
||||
|
||||
public Integer getMaxDepositTerm() {
|
||||
return maxDepositTerm;
|
||||
}
|
||||
|
||||
public EnumOptionData getMaxDepositTermType() {
|
||||
return maxDepositTermType;
|
||||
}
|
||||
|
||||
public BigDecimal getMinDepositAmount() {
|
||||
return minDepositAmount;
|
||||
}
|
||||
|
||||
public BigDecimal getDepositAmount() {
|
||||
return depositAmount;
|
||||
}
|
||||
|
||||
public BigDecimal getMaxDepositAmount() {
|
||||
return maxDepositAmount;
|
||||
}
|
||||
|
||||
public Integer getInMultiplesOfDepositTerm() {
|
||||
return inMultiplesOfDepositTerm;
|
||||
}
|
||||
|
||||
public EnumOptionData getInMultiplesOfDepositTermType() {
|
||||
return inMultiplesOfDepositTermType;
|
||||
}
|
||||
|
||||
public boolean isMandatoryDeposit() {
|
||||
return isMandatoryDeposit;
|
||||
}
|
||||
|
||||
public boolean isAllowWithdrawal() {
|
||||
return allowWithdrawal;
|
||||
}
|
||||
|
||||
public boolean isAdjustAdvanceTowardsFuturePayments() {
|
||||
return adjustAdvanceTowardsFuturePayments;
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* 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.time.LocalDate;
|
||||
|
||||
public final class SavingsAccountAnnualFeeData {
|
||||
|
||||
private final Long id;
|
||||
private final Long accountId;
|
||||
private final String accountNo;
|
||||
private final LocalDate nextAnnualFeeDueDate;
|
||||
|
||||
public static SavingsAccountAnnualFeeData instance(final Long id, final Long accountId, final String accountNo,
|
||||
final LocalDate nextAnnualFeeDueDate) {
|
||||
return new SavingsAccountAnnualFeeData(id, accountId, accountNo, nextAnnualFeeDueDate);
|
||||
}
|
||||
|
||||
private SavingsAccountAnnualFeeData(final Long id, final Long accountId, final String accountNo, final LocalDate nextAnnualFeeDueDate) {
|
||||
this.id = id;
|
||||
this.accountId = accountId;
|
||||
this.accountNo = accountNo;
|
||||
this.nextAnnualFeeDueDate = nextAnnualFeeDueDate;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public Long getAccountId() {
|
||||
return this.accountId;
|
||||
}
|
||||
|
||||
public LocalDate getNextAnnualFeeDueDate() {
|
||||
return this.nextAnnualFeeDueDate;
|
||||
}
|
||||
|
||||
public String getAccountNo() {
|
||||
return this.accountNo;
|
||||
}
|
||||
}
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* 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 static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_CHARGE_RESOURCE_NAME;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.amountParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargeIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.feeIntervalParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.feeOnMonthDayParamName;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.MonthDay;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class SavingsAccountChargeDataValidator {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountChargeDataValidator(final FromJsonHelper fromApiJsonHelper) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
}
|
||||
|
||||
public void validateAdd(final String json) {
|
||||
if (StringUtils.isBlank(json)) {
|
||||
throw new InvalidJsonException();
|
||||
}
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
|
||||
SavingsAccountConstant.SAVINGS_ACCOUNT_CHARGES_ADD_REQUEST_DATA_PARAMETERS);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_CHARGE_RESOURCE_NAME);
|
||||
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
final Long chargeId = this.fromApiJsonHelper.extractLongNamed(chargeIdParamName, element);
|
||||
baseDataValidator.reset().parameter(chargeIdParamName).value(chargeId).notNull().integerGreaterThanZero();
|
||||
|
||||
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(amountParamName, element);
|
||||
baseDataValidator.reset().parameter(amountParamName).value(amount).notNull().positiveAmount();
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(dueAsOfDateParamName, element)) {
|
||||
final LocalDate transactionDate = this.fromApiJsonHelper.extractLocalDateNamed(dueAsOfDateParamName, element);
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate).notNull();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(feeOnMonthDayParamName, element)) {
|
||||
final MonthDay monthDay = this.fromApiJsonHelper.extractMonthDayNamed(feeOnMonthDayParamName, element);
|
||||
baseDataValidator.reset().parameter(feeOnMonthDayParamName).value(monthDay).notNull();
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
public void validateUpdate(final String json) {
|
||||
if (StringUtils.isBlank(json)) {
|
||||
throw new InvalidJsonException();
|
||||
}
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
|
||||
SavingsAccountConstant.SAVINGS_ACCOUNT_CHARGES_ADD_REQUEST_DATA_PARAMETERS);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_CHARGE_RESOURCE_NAME);
|
||||
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(amountParamName, element);
|
||||
baseDataValidator.reset().parameter(amountParamName).value(amount).notNull().positiveAmount();
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(dueAsOfDateParamName, element)) {
|
||||
final LocalDate transactionDate = this.fromApiJsonHelper.extractLocalDateNamed(dueAsOfDateParamName, element);
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate).notNull();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(feeOnMonthDayParamName, element)) {
|
||||
final String monthDayFormat = this.fromApiJsonHelper.extractMonthDayFormatParameter(element.getAsJsonObject());
|
||||
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(element.getAsJsonObject());
|
||||
final MonthDay monthDay = this.fromApiJsonHelper.extractMonthDayNamed(feeOnMonthDayParamName, element.getAsJsonObject(),
|
||||
monthDayFormat, locale);
|
||||
baseDataValidator.reset().parameter(feeOnMonthDayParamName).value(monthDay).notNull();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(feeIntervalParamName, element)) {
|
||||
final Integer feeInterval = this.fromApiJsonHelper.extractIntegerNamed(feeIntervalParamName, element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter(feeIntervalParamName).value(feeInterval).notNull().inMinMaxRange(1, 12);
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
public void validatePayCharge(final String json) {
|
||||
if (StringUtils.isBlank(json)) {
|
||||
throw new InvalidJsonException();
|
||||
}
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
|
||||
SavingsAccountConstant.SAVINGS_ACCOUNT_CHARGES_PAY_CHARGE_REQUEST_DATA_PARAMETERS);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_CHARGE_RESOURCE_NAME);
|
||||
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(amountParamName, element);
|
||||
baseDataValidator.reset().parameter(amountParamName).value(amount).notNull().positiveAmount();
|
||||
|
||||
final LocalDate transactionDate = this.fromApiJsonHelper.extractLocalDateNamed(dueAsOfDateParamName, element);
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate).notNull();
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.data;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
|
||||
|
||||
public class SavingsAccountConstant extends SavingsApiConstants {
|
||||
|
||||
/**
|
||||
* These parameters will match the class level parameters of {@link SavingsProductData}. Where possible, we try to
|
||||
* get response 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, isGSIM, isParentAccount, accountNoParamName,
|
||||
externalIdParamName, clientIdParamName, groupIdParamName, productIdParamName, fieldOfficerIdParamName, submittedOnDateParamName,
|
||||
nominalAnnualInterestRateParamName, interestCompoundingPeriodTypeParamName, interestPostingPeriodTypeParamName,
|
||||
interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName,
|
||||
lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName,
|
||||
// withdrawalFeeAmountParamName, withdrawalFeeTypeParamName,
|
||||
withdrawalFeeForTransfersParamName, feeAmountParamName, feeOnMonthDayParamName, chargesParamName, allowOverdraftParamName,
|
||||
overdraftLimitParamName, minRequiredBalanceParamName, enforceMinRequiredBalanceParamName, lienAllowedParamName,
|
||||
maxAllowedLienLimitParamName, nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName,
|
||||
withHoldTaxParamName, datatables, gsimApplicationId, gsimLastApplication));
|
||||
|
||||
/**
|
||||
* These parameters will match the class level parameters of {@link SavingsAccountData}. Where possible, we try to
|
||||
* get response parameters to match those of request parameters.
|
||||
*/
|
||||
|
||||
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, retailEntriesParamName, childAccountIdParamName, noteParamName));
|
||||
|
||||
protected static final Set<String> SAVINGS_ACCOUNT_TRANSACTION_RESPONSE_DATA_PARAMETERS = new HashSet<>(
|
||||
Arrays.asList(idParamName, accountNoParamName));
|
||||
|
||||
protected static final Set<String> SAVINGS_ACCOUNT_ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<>(
|
||||
Arrays.asList(localeParamName, dateFormatParamName, activatedOnDateParamName));
|
||||
|
||||
protected static final Set<String> SAVINGS_ACCOUNT_CLOSE_REQUEST_DATA_PARAMETERS = new HashSet<>(
|
||||
Arrays.asList(localeParamName, dateFormatParamName, closedOnDateParamName, noteParamName, paymentTypeIdParamName,
|
||||
withdrawBalanceParamName, transactionAccountNumberParamName, checkNumberParamName, routingCodeParamName,
|
||||
receiptNumberParamName, bankNumberParamName, postInterestValidationOnClosure));
|
||||
|
||||
protected static final Set<String> SAVINGS_ACCOUNT_CHARGES_ADD_REQUEST_DATA_PARAMETERS = new HashSet<>(
|
||||
Arrays.asList(chargeIdParamName, amountParamName, dueAsOfDateParamName, dateFormatParamName, localeParamName,
|
||||
feeOnMonthDayParamName, monthDayFormatParamName, feeIntervalParamName));
|
||||
|
||||
protected static final Set<String> SAVINGS_ACCOUNT_CHARGES_PAY_CHARGE_REQUEST_DATA_PARAMETERS = new HashSet<>(
|
||||
Arrays.asList(amountParamName, dueAsOfDateParamName, dateFormatParamName, localeParamName, noteParamName));
|
||||
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* 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.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.group.domain.Group;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
|
||||
public class SavingsAccountDataDTO {
|
||||
|
||||
private final Client client;
|
||||
private final Group group;
|
||||
private final Long savingsProductId;
|
||||
private final LocalDate applicationDate;
|
||||
private final AppUser appliedBy;
|
||||
private final DateTimeFormatter fmt;
|
||||
|
||||
public SavingsAccountDataDTO(final Client client, final Group group, final Long savingsProductId, final LocalDate applicationDate,
|
||||
final AppUser appliedBy, final DateTimeFormatter fmt) {
|
||||
this.client = client;
|
||||
this.group = group;
|
||||
this.savingsProductId = savingsProductId;
|
||||
this.applicationDate = applicationDate;
|
||||
this.appliedBy = appliedBy;
|
||||
this.fmt = fmt;
|
||||
}
|
||||
|
||||
public Client getClient() {
|
||||
return this.client;
|
||||
}
|
||||
|
||||
public Group getGroup() {
|
||||
return this.group;
|
||||
}
|
||||
|
||||
public Long getSavingsProduct() {
|
||||
return this.savingsProductId;
|
||||
}
|
||||
|
||||
public LocalDate getApplicationDate() {
|
||||
return this.applicationDate;
|
||||
}
|
||||
|
||||
public AppUser getAppliedBy() {
|
||||
return this.appliedBy;
|
||||
}
|
||||
|
||||
public DateTimeFormatter getFmt() {
|
||||
return this.fmt;
|
||||
}
|
||||
}
|
||||
+534
@@ -0,0 +1,534 @@
|
||||
/**
|
||||
* 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 static org.apache.fineract.portfolio.savings.SavingsApiConstants.accountNoParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.allowOverdraftParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.amountParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargeIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargesParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.clientIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.externalIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.feeIntervalParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.feeOnMonthDayParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.fieldOfficerIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.groupIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCalculationDaysInYearTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCalculationTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCompoundingPeriodTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestPostingPeriodTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.lienAllowedParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.maxAllowedLienLimitParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.minOverdraftForInterestCalculationParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.minRequiredOpeningBalanceParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateOverdraftParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.productIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.submittedOnDateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHoldTaxParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.MonthDay;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
|
||||
import org.apache.fineract.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class SavingsAccountDataValidator {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountDataValidator(final FromJsonHelper fromApiJsonHelper) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
}
|
||||
|
||||
public void validateForSubmit(final String json) {
|
||||
|
||||
if (StringUtils.isBlank(json)) {
|
||||
throw new InvalidJsonException();
|
||||
}
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
|
||||
SavingsAccountConstant.SAVINGS_ACCOUNT_REQUEST_DATA_PARAMETERS);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
final Long clientId = this.fromApiJsonHelper.extractLongNamed(clientIdParamName, element);
|
||||
if (clientId != null) {
|
||||
baseDataValidator.reset().parameter(clientIdParamName).value(clientId).longGreaterThanZero();
|
||||
}
|
||||
|
||||
final Long groupId = this.fromApiJsonHelper.extractLongNamed(groupIdParamName, element);
|
||||
if (groupId != null) {
|
||||
baseDataValidator.reset().parameter(groupIdParamName).value(groupId).longGreaterThanZero();
|
||||
}
|
||||
|
||||
if (clientId == null && groupId == null) {
|
||||
baseDataValidator.reset().parameter(clientIdParamName).value(clientId).notNull().integerGreaterThanZero();
|
||||
}
|
||||
|
||||
final Long productId = this.fromApiJsonHelper.extractLongNamed(productIdParamName, element);
|
||||
baseDataValidator.reset().parameter(productIdParamName).value(productId).notNull().integerGreaterThanZero();
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(fieldOfficerIdParamName, element)) {
|
||||
final Long fieldOfficerId = this.fromApiJsonHelper.extractLongNamed(fieldOfficerIdParamName, element);
|
||||
baseDataValidator.reset().parameter(fieldOfficerIdParamName).value(fieldOfficerId).ignoreIfNull().integerGreaterThanZero();
|
||||
}
|
||||
|
||||
final LocalDate submittedOnDate = this.fromApiJsonHelper.extractLocalDateNamed(submittedOnDateParamName, element);
|
||||
baseDataValidator.reset().parameter(submittedOnDateParamName).value(submittedOnDate).notNull();
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(accountNoParamName, element)) {
|
||||
final String accountNo = this.fromApiJsonHelper.extractStringNamed(accountNoParamName, element);
|
||||
baseDataValidator.reset().parameter(accountNoParamName).value(accountNo).notBlank().notExceedingLengthOf(20);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(externalIdParamName, element)) {
|
||||
final String externalId = this.fromApiJsonHelper.extractStringNamed(externalIdParamName, element);
|
||||
baseDataValidator.reset().parameter(externalIdParamName).value(externalId).notExceedingLengthOf(100);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(nominalAnnualInterestRateParamName, element)) {
|
||||
final BigDecimal interestRate = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(nominalAnnualInterestRateParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(nominalAnnualInterestRateParamName).value(interestRate).notNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(interestCompoundingPeriodTypeParamName, element)) {
|
||||
final Integer interestCompoundingPeriodType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(interestCompoundingPeriodTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(interestCompoundingPeriodTypeParamName).value(interestCompoundingPeriodType).notNull()
|
||||
.isOneOfTheseValues(SavingsCompoundingInterestPeriodType.integerValues());
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(interestPostingPeriodTypeParamName, element)) {
|
||||
final Integer interestPostingPeriodType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(interestPostingPeriodTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(interestPostingPeriodTypeParamName).value(interestPostingPeriodType).notNull()
|
||||
.isOneOfTheseValues(SavingsPostingInterestPeriodType.integerValues());
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(interestCalculationTypeParamName, element)) {
|
||||
final Integer interestCalculationType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(interestCalculationTypeParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(interestCalculationTypeParamName).value(interestCalculationType).notNull()
|
||||
.isOneOfTheseValues(SavingsInterestCalculationType.integerValues());
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(interestCalculationDaysInYearTypeParamName, element)) {
|
||||
final Integer interestCalculationDaysInYearType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(interestCalculationDaysInYearTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(interestCalculationDaysInYearTypeParamName).value(interestCalculationDaysInYearType)
|
||||
.notNull().isOneOfTheseValues(SavingsInterestCalculationDaysInYearType.integerValues());
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(minRequiredOpeningBalanceParamName, element)) {
|
||||
final BigDecimal minOpeningBalance = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minRequiredOpeningBalanceParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(minRequiredOpeningBalanceParamName).value(minOpeningBalance).zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyParamName, element)) {
|
||||
|
||||
final Integer lockinPeriodFrequency = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(lockinPeriodFrequencyParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).integerZeroOrGreater();
|
||||
|
||||
if (lockinPeriodFrequency != null) {
|
||||
final Integer lockinPeriodFrequencyType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(lockinPeriodFrequencyTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).notNull()
|
||||
.inMinMaxRange(0, 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyTypeParamName, element)) {
|
||||
final Integer lockinPeriodFrequencyType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(lockinPeriodFrequencyTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).inMinMaxRange(0, 3);
|
||||
|
||||
if (lockinPeriodFrequencyType != null) {
|
||||
final Integer lockinPeriodFrequency = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(lockinPeriodFrequencyParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).notNull()
|
||||
.integerZeroOrGreater();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeForTransfersParamName, element)) {
|
||||
final Boolean isWithdrawalFeeApplicableForTransfers = this.fromApiJsonHelper
|
||||
.extractBooleanNamed(withdrawalFeeForTransfersParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeForTransfersParamName).value(isWithdrawalFeeApplicableForTransfers)
|
||||
.ignoreIfNull().validateForBooleanValue();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withHoldTaxParamName, element)) {
|
||||
final String withHoldTax = this.fromApiJsonHelper.extractStringNamed(withHoldTaxParamName, element);
|
||||
baseDataValidator.reset().parameter(withHoldTaxParamName).value(withHoldTax).ignoreIfNull().validateForBooleanValue();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(SavingsApiConstants.datatables, element)) {
|
||||
final JsonArray datatables = this.fromApiJsonHelper.extractJsonArrayNamed(SavingsApiConstants.datatables, element);
|
||||
baseDataValidator.reset().parameter(SavingsApiConstants.datatables).value(datatables).notNull().jsonArrayNotEmpty();
|
||||
}
|
||||
|
||||
validateSavingsCharges(element, baseDataValidator);
|
||||
|
||||
validateOverdraftParams(baseDataValidator, element);
|
||||
validateLienParams(baseDataValidator, element);
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
private void validateSavingsCharges(final JsonElement element, final DataValidatorBuilder baseDataValidator) {
|
||||
|
||||
if (element.isJsonObject()) {
|
||||
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
||||
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
|
||||
final String monthDayFormat = this.fromApiJsonHelper.extractMonthDayFormatParameter(topLevelJsonElement);
|
||||
if (topLevelJsonElement.has(chargesParamName) && topLevelJsonElement.get(chargesParamName).isJsonArray()) {
|
||||
final JsonArray array = topLevelJsonElement.get(chargesParamName).getAsJsonArray();
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
|
||||
final JsonObject savingsChargeElement = array.get(i).getAsJsonObject();
|
||||
|
||||
// final Long id =
|
||||
// this.fromApiJsonHelper.extractLongNamed(idParamName,
|
||||
// savingsChargeElement);
|
||||
|
||||
final Long chargeId = this.fromApiJsonHelper.extractLongNamed(chargeIdParamName, savingsChargeElement);
|
||||
baseDataValidator.reset().parameter(chargeIdParamName).value(chargeId).longGreaterThanZero();
|
||||
|
||||
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalNamed(amountParamName, savingsChargeElement, locale);
|
||||
baseDataValidator.reset().parameter(amountParamName).value(amount).notNull().positiveAmount();
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(feeOnMonthDayParamName, savingsChargeElement)) {
|
||||
final MonthDay monthDay = this.fromApiJsonHelper.extractMonthDayNamed(feeOnMonthDayParamName, savingsChargeElement,
|
||||
monthDayFormat, locale);
|
||||
baseDataValidator.reset().parameter(feeOnMonthDayParamName).value(monthDay).notNull();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(feeIntervalParamName, savingsChargeElement)) {
|
||||
final Integer feeInterval = this.fromApiJsonHelper.extractIntegerNamed(feeIntervalParamName, savingsChargeElement,
|
||||
Locale.getDefault());
|
||||
baseDataValidator.reset().parameter(feeIntervalParamName).value(feeInterval).notNull().inMinMaxRange(1, 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void validateForUpdate(final String json) {
|
||||
|
||||
if (StringUtils.isBlank(json)) {
|
||||
throw new InvalidJsonException();
|
||||
}
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
|
||||
SavingsAccountConstant.SAVINGS_ACCOUNT_REQUEST_DATA_PARAMETERS);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
Long clientId = null;
|
||||
if (this.fromApiJsonHelper.parameterExists(clientIdParamName, element)) {
|
||||
clientId = this.fromApiJsonHelper.extractLongNamed(clientIdParamName, element);
|
||||
baseDataValidator.reset().parameter(clientIdParamName).value(clientId).ignoreIfNull().longGreaterThanZero();
|
||||
|
||||
Long groupId = null;
|
||||
if (this.fromApiJsonHelper.parameterExists(productIdParamName, element)) {
|
||||
groupId = this.fromApiJsonHelper.extractLongNamed(groupIdParamName, element);
|
||||
baseDataValidator.reset().parameter(groupIdParamName).value(groupId).ignoreIfNull().longGreaterThanZero();
|
||||
}
|
||||
|
||||
if (clientId == null && groupId == null) {
|
||||
// either clientId or groupId must exists if param passed for
|
||||
// update.
|
||||
baseDataValidator.reset().parameter(clientIdParamName).value(clientId).notNull().integerGreaterThanZero();
|
||||
}
|
||||
}
|
||||
|
||||
Long groupId = null;
|
||||
if (this.fromApiJsonHelper.parameterExists(groupIdParamName, element)) {
|
||||
groupId = this.fromApiJsonHelper.extractLongNamed(groupIdParamName, element);
|
||||
baseDataValidator.reset().parameter(groupIdParamName).value(groupId).ignoreIfNull().longGreaterThanZero();
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(clientIdParamName, element)) {
|
||||
clientId = this.fromApiJsonHelper.extractLongNamed(clientIdParamName, element);
|
||||
baseDataValidator.reset().parameter(clientIdParamName).value(clientId).ignoreIfNull().longGreaterThanZero();
|
||||
}
|
||||
|
||||
if (clientId == null && groupId == null) {
|
||||
// either clientId or groupId must exists if param passed for
|
||||
// update.
|
||||
baseDataValidator.reset().parameter(clientIdParamName).value(clientId).notNull().integerGreaterThanZero();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(productIdParamName, element)) {
|
||||
final Long productId = this.fromApiJsonHelper.extractLongNamed(productIdParamName, element);
|
||||
baseDataValidator.reset().parameter(productIdParamName).value(productId).notNull().integerGreaterThanZero();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(fieldOfficerIdParamName, element)) {
|
||||
final Long fieldOfficerId = this.fromApiJsonHelper.extractLongNamed(fieldOfficerIdParamName, element);
|
||||
baseDataValidator.reset().parameter(fieldOfficerIdParamName).value(fieldOfficerId).ignoreIfNull().integerGreaterThanZero();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(submittedOnDateParamName, element)) {
|
||||
final LocalDate submittedOnDate = this.fromApiJsonHelper.extractLocalDateNamed(submittedOnDateParamName, element);
|
||||
baseDataValidator.reset().parameter(submittedOnDateParamName).value(submittedOnDate).notNull();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(accountNoParamName, element)) {
|
||||
final String accountNo = this.fromApiJsonHelper.extractStringNamed(accountNoParamName, element);
|
||||
baseDataValidator.reset().parameter(accountNoParamName).value(accountNo).notBlank().notExceedingLengthOf(20);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(externalIdParamName, element)) {
|
||||
final String externalId = this.fromApiJsonHelper.extractStringNamed(externalIdParamName, element);
|
||||
baseDataValidator.reset().parameter(externalIdParamName).value(externalId).notExceedingLengthOf(100);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(nominalAnnualInterestRateParamName, element)) {
|
||||
final BigDecimal interestRate = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(nominalAnnualInterestRateParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(nominalAnnualInterestRateParamName).value(interestRate).notNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(interestCompoundingPeriodTypeParamName, element)) {
|
||||
final Integer interestCompoundingPeriodType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(interestCompoundingPeriodTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(interestCompoundingPeriodTypeParamName).value(interestCompoundingPeriodType).notNull()
|
||||
.isOneOfTheseValues(SavingsCompoundingInterestPeriodType.integerValues());
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(interestPostingPeriodTypeParamName, element)) {
|
||||
final Integer interestPostingPeriodType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(interestPostingPeriodTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(interestPostingPeriodTypeParamName).value(interestPostingPeriodType).notNull()
|
||||
.isOneOfTheseValues(SavingsPostingInterestPeriodType.integerValues());
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(interestCalculationTypeParamName, element)) {
|
||||
final Integer interestCalculationType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(interestCalculationTypeParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(interestCalculationTypeParamName).value(interestCalculationType).notNull()
|
||||
.isOneOfTheseValues(SavingsInterestCalculationType.integerValues());
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(interestCalculationDaysInYearTypeParamName, element)) {
|
||||
final Integer interestCalculationDaysInYearType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(interestCalculationDaysInYearTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(interestCalculationDaysInYearTypeParamName).value(interestCalculationDaysInYearType)
|
||||
.notNull().isOneOfTheseValues(SavingsInterestCalculationDaysInYearType.integerValues());
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(minRequiredOpeningBalanceParamName, element)) {
|
||||
final BigDecimal minOpeningBalance = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minRequiredOpeningBalanceParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(minRequiredOpeningBalanceParamName).value(minOpeningBalance).ignoreIfNull()
|
||||
.zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyParamName, element)) {
|
||||
final Integer lockinPeriodFrequency = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(lockinPeriodFrequencyParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).ignoreIfNull()
|
||||
.integerZeroOrGreater();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyTypeParamName, element)) {
|
||||
final Integer lockinPeriodFrequencyType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(lockinPeriodFrequencyTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).inMinMaxRange(0, 3);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeForTransfersParamName, element)) {
|
||||
final Boolean isWithdrawalFeeApplicableForTransfers = this.fromApiJsonHelper
|
||||
.extractBooleanNamed(withdrawalFeeForTransfersParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeForTransfersParamName).value(isWithdrawalFeeApplicableForTransfers)
|
||||
.ignoreIfNull().validateForBooleanValue();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withHoldTaxParamName, element)) {
|
||||
final String withHoldTax = this.fromApiJsonHelper.extractStringNamed(withHoldTaxParamName, element);
|
||||
baseDataValidator.reset().parameter(withHoldTaxParamName).value(withHoldTax).ignoreIfNull().validateForBooleanValue();
|
||||
}
|
||||
|
||||
validateOverdraftParams(baseDataValidator, element);
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateLienParams(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
||||
if (this.fromApiJsonHelper.parameterExists(lienAllowedParamName, element)) {
|
||||
final Boolean lienAllowed = this.fromApiJsonHelper.extractBooleanNamed(lienAllowedParamName, element);
|
||||
baseDataValidator.reset().parameter(lienAllowedParamName).value(lienAllowed).ignoreIfNull().validateForBooleanValue();
|
||||
}
|
||||
|
||||
if (BooleanUtils.isTrue(this.fromApiJsonHelper.extractBooleanNamed(lienAllowedParamName, element))) {
|
||||
final BigDecimal maxAllowedLienLimit = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxAllowedLienLimitParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(maxAllowedLienLimitParamName).value(maxAllowedLienLimit).ignoreIfNull()
|
||||
.zeroOrPositiveAmount();
|
||||
}
|
||||
if (BooleanUtils.isTrue(this.fromApiJsonHelper.extractBooleanNamed(lienAllowedParamName, element))
|
||||
&& BooleanUtils.isTrue(this.fromApiJsonHelper.extractBooleanNamed(allowOverdraftParamName, element))) {
|
||||
final BigDecimal maxAllowedLienLimit = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxAllowedLienLimitParamName,
|
||||
element);
|
||||
final BigDecimal overdraftLimit = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(overdraftLimitParamName, element);
|
||||
if (overdraftLimit.compareTo(maxAllowedLienLimit) > 0) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("Overdraft.limit.can.not.be.greater.than.lien.limit");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateOverdraftParams(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
||||
if (this.fromApiJsonHelper.parameterExists(allowOverdraftParamName, element)) {
|
||||
final Boolean allowOverdraft = this.fromApiJsonHelper.extractBooleanNamed(allowOverdraftParamName, element);
|
||||
baseDataValidator.reset().parameter(allowOverdraftParamName).value(allowOverdraft).ignoreIfNull().validateForBooleanValue();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(overdraftLimitParamName, element)) {
|
||||
final BigDecimal overdraftLimit = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(overdraftLimitParamName, element);
|
||||
baseDataValidator.reset().parameter(overdraftLimitParamName).value(overdraftLimit).ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(nominalAnnualInterestRateOverdraftParamName, element)) {
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft = this.fromApiJsonHelper
|
||||
.extractBigDecimalWithLocaleNamed(nominalAnnualInterestRateOverdraftParamName, element);
|
||||
baseDataValidator.reset().parameter(nominalAnnualInterestRateOverdraftParamName).value(nominalAnnualInterestRateOverdraft)
|
||||
.ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(minOverdraftForInterestCalculationParamName, element)) {
|
||||
final BigDecimal minOverdraftForInterestCalculation = this.fromApiJsonHelper
|
||||
.extractBigDecimalWithLocaleNamed(minOverdraftForInterestCalculationParamName, element);
|
||||
baseDataValidator.reset().parameter(minOverdraftForInterestCalculationParamName).value(minOverdraftForInterestCalculation)
|
||||
.ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void validateForAssignSavingsOfficer(final String json) {
|
||||
|
||||
if (StringUtils.isBlank(json)) {
|
||||
throw new InvalidJsonException();
|
||||
}
|
||||
|
||||
final Set<String> supportedParameters = new HashSet<>(
|
||||
Arrays.asList("fromSavingsOfficerId", "toSavingsOfficerId", "assignmentDate", "locale", "dateFormat"));
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
final Long toSavingsOfficerId = this.fromApiJsonHelper.extractLongNamed("toSavingsOfficerId", element);
|
||||
baseDataValidator.reset().parameter("toSavingsOfficerId").value(toSavingsOfficerId).notNull().integerGreaterThanZero();
|
||||
|
||||
final String assignmentDateStr = this.fromApiJsonHelper.extractStringNamed("assignmentDate", element);
|
||||
baseDataValidator.reset().parameter("assignmentDate").value(assignmentDateStr).notBlank();
|
||||
|
||||
if (!StringUtils.isBlank(assignmentDateStr)) {
|
||||
final LocalDate assignmentDate = this.fromApiJsonHelper.extractLocalDateNamed("assignmentDate", element);
|
||||
baseDataValidator.reset().parameter("assignmentDate").value(assignmentDate).notNull();
|
||||
}
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
dataValidationErrors);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void validateForUnAssignSavingsOfficer(final String json) {
|
||||
if (StringUtils.isBlank(json)) {
|
||||
throw new InvalidJsonException();
|
||||
}
|
||||
|
||||
final Set<String> supportedParameters = new HashSet<>(Arrays.asList("unassignedDate", "locale", "dateFormat"));
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
final String unassignedDateStr = this.fromApiJsonHelper.extractStringNamed("unassignedDate", element);
|
||||
baseDataValidator.reset().parameter("unassignedDate").value(unassignedDateStr).notBlank();
|
||||
|
||||
if (!StringUtils.isBlank(unassignedDateStr)) {
|
||||
final LocalDate unassignedDate = this.fromApiJsonHelper.extractLocalDateNamed("unassignedDate", element);
|
||||
baseDataValidator.reset().parameter("unassignedDate").value(unassignedDate).notNull();
|
||||
}
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
dataValidationErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* 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.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
|
||||
public class SavingsAccountTransactionDTO {
|
||||
|
||||
private final DateTimeFormatter formatter;
|
||||
private final LocalDate transactionDate;
|
||||
private final BigDecimal transactionAmount;
|
||||
private final PaymentDetail paymentDetail;
|
||||
private final Long savingsAccountId;
|
||||
private final Integer depositAccountType;
|
||||
|
||||
/**
|
||||
* This constructor is used for bulk deposit transactions
|
||||
*
|
||||
* @param formatter
|
||||
* @param transactionDate
|
||||
* @param transactionAmount
|
||||
* @param paymentDetail
|
||||
* @param savingsAccountId
|
||||
*/
|
||||
public SavingsAccountTransactionDTO(DateTimeFormatter formatter, LocalDate transactionDate, BigDecimal transactionAmount,
|
||||
PaymentDetail paymentDetail, Long savingsAccountId, final Integer depositAccountType) {
|
||||
this.formatter = formatter;
|
||||
this.transactionDate = transactionDate;
|
||||
this.transactionAmount = transactionAmount;
|
||||
this.paymentDetail = paymentDetail;
|
||||
this.savingsAccountId = savingsAccountId;
|
||||
this.depositAccountType = depositAccountType;
|
||||
}
|
||||
|
||||
public DateTimeFormatter getFormatter() {
|
||||
return this.formatter;
|
||||
}
|
||||
|
||||
public LocalDate getTransactionDate() {
|
||||
return this.transactionDate;
|
||||
}
|
||||
|
||||
public BigDecimal getTransactionAmount() {
|
||||
return this.transactionAmount;
|
||||
}
|
||||
|
||||
public PaymentDetail getPaymentDetail() {
|
||||
return this.paymentDetail;
|
||||
}
|
||||
|
||||
public Long getSavingsAccountId() {
|
||||
return this.savingsAccountId;
|
||||
}
|
||||
|
||||
public Integer getAccountType() {
|
||||
return this.depositAccountType;
|
||||
}
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.data;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public final class SavingsActivation {
|
||||
|
||||
private final transient Integer rowIndex;
|
||||
|
||||
private final LocalDate activatedOnDate;
|
||||
|
||||
private final String dateFormat;
|
||||
|
||||
private final String locale;
|
||||
|
||||
public static SavingsActivation importInstance(LocalDate activatedOnDate, Integer rowIndex, String locale, String dateFormat) {
|
||||
return new SavingsActivation(activatedOnDate, rowIndex, locale, dateFormat);
|
||||
}
|
||||
|
||||
private SavingsActivation(LocalDate activatedOnDate, Integer rowIndex, String locale, String dateFormat) {
|
||||
this.activatedOnDate = activatedOnDate;
|
||||
this.rowIndex = rowIndex;
|
||||
this.dateFormat = dateFormat;
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
public LocalDate getActivatedOnDate() {
|
||||
return activatedOnDate;
|
||||
}
|
||||
|
||||
public String getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
public String getDateFormat() {
|
||||
return dateFormat;
|
||||
}
|
||||
|
||||
public Integer getRowIndex() {
|
||||
return rowIndex;
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 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.time.LocalDate;
|
||||
|
||||
public final class SavingsApproval {
|
||||
|
||||
private final transient Integer rowIndex;
|
||||
|
||||
private final LocalDate approvedOnDate;
|
||||
|
||||
private final String dateFormat;
|
||||
|
||||
private final String locale;
|
||||
|
||||
private final String note;
|
||||
|
||||
public static SavingsApproval importInstance(LocalDate approvedOnDate, Integer rowIndex, String locale, String dateFormat) {
|
||||
return new SavingsApproval(approvedOnDate, rowIndex, locale, dateFormat);
|
||||
}
|
||||
|
||||
private SavingsApproval(LocalDate approvedOnDate, Integer rowIndex, String locale, String dateFormat) {
|
||||
this.approvedOnDate = approvedOnDate;
|
||||
this.rowIndex = rowIndex;
|
||||
this.dateFormat = dateFormat;
|
||||
this.locale = locale;
|
||||
this.note = "";
|
||||
}
|
||||
|
||||
public LocalDate getApprovedOnDate() {
|
||||
return approvedOnDate;
|
||||
}
|
||||
|
||||
public String getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
public String getDateFormat() {
|
||||
return dateFormat;
|
||||
}
|
||||
|
||||
public Integer getRowIndex() {
|
||||
return rowIndex;
|
||||
}
|
||||
|
||||
public String getNote() {
|
||||
return note;
|
||||
}
|
||||
}
|
||||
+704
@@ -0,0 +1,704 @@
|
||||
/**
|
||||
* 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 static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_PRODUCT_RESOURCE_NAME;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.allowOverdraftParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.currencyCodeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.daysToDormancyParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.daysToEscheatParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.daysToInactiveParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.descriptionParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.digitsAfterDecimalParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.feeAmountParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.feeOnMonthDayParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.inMultiplesOfParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCalculationDaysInYearTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCalculationTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCompoundingPeriodTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestPostingPeriodTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.isDormancyTrackingActiveParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.lienAllowedParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.maxAllowedLienLimitParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.minBalanceForInterestCalculationParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.minOverdraftForInterestCalculationParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.minRequiredOpeningBalanceParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nameParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateOverdraftParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.shortNameParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.taxGroupIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHoldTaxParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.MonthDay;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.SavingProductAccountingParams;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
|
||||
import org.apache.fineract.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProduct;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class SavingsProductDataValidator {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private static final Set<String> SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(
|
||||
SavingsApiConstants.localeParamName, SavingsApiConstants.monthDayFormatParamName, nameParamName, shortNameParamName,
|
||||
descriptionParamName, currencyCodeParamName, digitsAfterDecimalParamName, inMultiplesOfParamName,
|
||||
nominalAnnualInterestRateParamName, interestCompoundingPeriodTypeParamName, interestPostingPeriodTypeParamName,
|
||||
interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName,
|
||||
lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName, SavingsApiConstants.withdrawalFeeAmountParamName,
|
||||
SavingsApiConstants.withdrawalFeeTypeParamName, withdrawalFeeForTransfersParamName, feeAmountParamName, feeOnMonthDayParamName,
|
||||
SavingsApiConstants.accountingRuleParamName, SavingsApiConstants.chargesParamName,
|
||||
SavingProductAccountingParams.INCOME_FROM_FEES.getValue(), SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(),
|
||||
SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(),
|
||||
SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
|
||||
SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(),
|
||||
SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), SavingProductAccountingParams.FEE_INCOME_ACCOUNT_MAPPING.getValue(),
|
||||
SavingProductAccountingParams.PENALTY_INCOME_ACCOUNT_MAPPING.getValue(),
|
||||
SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(),
|
||||
SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue(), isDormancyTrackingActiveParamName, daysToDormancyParamName,
|
||||
daysToInactiveParamName, daysToEscheatParamName, allowOverdraftParamName, overdraftLimitParamName,
|
||||
nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName,
|
||||
SavingsApiConstants.minRequiredBalanceParamName, SavingsApiConstants.enforceMinRequiredBalanceParamName,
|
||||
SavingsApiConstants.maxAllowedLienLimitParamName, SavingsApiConstants.lienAllowedParamName,
|
||||
minBalanceForInterestCalculationParamName, withHoldTaxParamName, taxGroupIdParamName));
|
||||
|
||||
@Autowired
|
||||
public SavingsProductDataValidator(final FromJsonHelper fromApiJsonHelper) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
}
|
||||
|
||||
public void validateForCreate(final String json) {
|
||||
|
||||
if (StringUtils.isBlank(json)) {
|
||||
throw new InvalidJsonException();
|
||||
}
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_PRODUCT_RESOURCE_NAME);
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
final String name = this.fromApiJsonHelper.extractStringNamed(nameParamName, element);
|
||||
baseDataValidator.reset().parameter(nameParamName).value(name).notBlank().notExceedingLengthOf(100);
|
||||
|
||||
final String shortName = this.fromApiJsonHelper.extractStringNamed(shortNameParamName, element);
|
||||
baseDataValidator.reset().parameter(shortNameParamName).value(shortName).notBlank().notExceedingLengthOf(4);
|
||||
|
||||
final String currencyCode = this.fromApiJsonHelper.extractStringNamed(currencyCodeParamName, element);
|
||||
baseDataValidator.reset().parameter(currencyCodeParamName).value(currencyCode).notBlank();
|
||||
|
||||
final Integer digitsAfterDecimal = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(digitsAfterDecimalParamName, element);
|
||||
baseDataValidator.reset().parameter(digitsAfterDecimalParamName).value(digitsAfterDecimal).notNull().inMinMaxRange(0, 6);
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(inMultiplesOfParamName, element)) {
|
||||
final Integer inMultiplesOf = this.fromApiJsonHelper.extractIntegerNamed(inMultiplesOfParamName, element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter(inMultiplesOfParamName).value(inMultiplesOf).ignoreIfNull().integerZeroOrGreater();
|
||||
}
|
||||
final BigDecimal nominalAnnualInterestRate = this.fromApiJsonHelper
|
||||
.extractBigDecimalWithLocaleNamed(nominalAnnualInterestRateParamName, element);
|
||||
baseDataValidator.reset().parameter(nominalAnnualInterestRateParamName).value(nominalAnnualInterestRate).notNull()
|
||||
.zeroOrPositiveAmount();
|
||||
|
||||
final Integer interestCompoundingPeriodType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(interestCompoundingPeriodTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(interestCompoundingPeriodTypeParamName).value(interestCompoundingPeriodType).notNull()
|
||||
.isOneOfTheseValues(SavingsCompoundingInterestPeriodType.integerValues());
|
||||
|
||||
final Integer interestPostingPeriodType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(interestPostingPeriodTypeParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(interestPostingPeriodTypeParamName).value(interestPostingPeriodType).notNull()
|
||||
.isOneOfTheseValues(SavingsPostingInterestPeriodType.integerValues());
|
||||
|
||||
final Integer interestCalculationType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(interestCalculationTypeParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(interestCalculationTypeParamName).value(interestCalculationType).notNull()
|
||||
.isOneOfTheseValues(SavingsInterestCalculationType.integerValues());
|
||||
|
||||
final Integer interestCalculationDaysInYearType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(interestCalculationDaysInYearTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(interestCalculationDaysInYearTypeParamName).value(interestCalculationDaysInYearType).notNull()
|
||||
.isOneOfTheseValues(SavingsInterestCalculationDaysInYearType.integerValues());
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(descriptionParamName, element)) {
|
||||
final String description = this.fromApiJsonHelper.extractStringNamed(descriptionParamName, element);
|
||||
baseDataValidator.reset().parameter(descriptionParamName).value(description).ignoreIfNull().notExceedingLengthOf(500);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(minRequiredOpeningBalanceParamName, element)) {
|
||||
final BigDecimal minOpeningBalance = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minRequiredOpeningBalanceParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(minRequiredOpeningBalanceParamName).value(minOpeningBalance).zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyParamName, element)) {
|
||||
|
||||
final Integer lockinPeriodFrequency = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(lockinPeriodFrequencyParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).integerZeroOrGreater();
|
||||
|
||||
if (lockinPeriodFrequency != null) {
|
||||
final Integer lockinPeriodFrequencyType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(lockinPeriodFrequencyTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).notNull()
|
||||
.inMinMaxRange(0, 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyTypeParamName, element)) {
|
||||
final Integer lockinPeriodFrequencyType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(lockinPeriodFrequencyTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).inMinMaxRange(0, 3);
|
||||
|
||||
if (lockinPeriodFrequencyType != null) {
|
||||
final Integer lockinPeriodFrequency = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(lockinPeriodFrequencyParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).notNull()
|
||||
.integerZeroOrGreater();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if (this.fromApiJsonHelper.parameterExists(withdrawalFeeAmountParamName, element)) {
|
||||
*
|
||||
* final BigDecimal withdrawalFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed
|
||||
* (withdrawalFeeAmountParamName, element); baseDataValidator.reset().parameter
|
||||
* (withdrawalFeeAmountParamName).value (withdrawalFeeAmount).zeroOrPositiveAmount();
|
||||
*
|
||||
* if (withdrawalFeeAmount != null) { final Integer withdrawalFeeType =
|
||||
* this.fromApiJsonHelper.extractIntegerSansLocaleNamed( withdrawalFeeTypeParamName, element);
|
||||
* baseDataValidator.reset().parameter (withdrawalFeeTypeParamName).value(withdrawalFeeType)
|
||||
* .isOneOfTheseValues(SavingsWithdrawalFeesType.integerValues()); } }
|
||||
*
|
||||
* if (this.fromApiJsonHelper.parameterExists(withdrawalFeeTypeParamName, element)) { final Integer
|
||||
* withdrawalFeeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed (withdrawalFeeTypeParamName,
|
||||
* element); baseDataValidator.reset().parameter
|
||||
* (withdrawalFeeTypeParamName).value(withdrawalFeeType).ignoreIfNull() .isOneOfTheseValues(1, 2);
|
||||
*
|
||||
* if (withdrawalFeeType != null) { final BigDecimal withdrawalFeeAmount =
|
||||
* this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed( withdrawalFeeAmountParamName, element);
|
||||
* baseDataValidator.reset().parameter (withdrawalFeeAmountParamName).value(withdrawalFeeAmount).notNull()
|
||||
* .zeroOrPositiveAmount(); } }
|
||||
*/
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeForTransfersParamName, element)) {
|
||||
final Boolean isWithdrawalFeeApplicableForTransfers = this.fromApiJsonHelper
|
||||
.extractBooleanNamed(withdrawalFeeForTransfersParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeForTransfersParamName).value(isWithdrawalFeeApplicableForTransfers)
|
||||
.ignoreIfNull().validateForBooleanValue();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(feeAmountParamName, element)) {
|
||||
final BigDecimal annualFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(feeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(feeAmountParamName).value(annualFeeAmount).zeroOrPositiveAmount();
|
||||
|
||||
if (annualFeeAmount != null) {
|
||||
final MonthDay monthDayOfAnnualFee = this.fromApiJsonHelper.extractMonthDayNamed(feeOnMonthDayParamName, element);
|
||||
baseDataValidator.reset().parameter(feeOnMonthDayParamName).value(monthDayOfAnnualFee).notNull();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(feeOnMonthDayParamName, element)) {
|
||||
|
||||
final MonthDay monthDayOfAnnualFee = this.fromApiJsonHelper.extractMonthDayNamed(feeOnMonthDayParamName, element);
|
||||
if (monthDayOfAnnualFee != null) {
|
||||
final BigDecimal annualFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(feeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(feeAmountParamName).value(annualFeeAmount).notNull().zeroOrPositiveAmount();
|
||||
}
|
||||
}
|
||||
|
||||
// dormancy
|
||||
final Boolean isDormancyActive = this.fromApiJsonHelper.extractBooleanNamed(isDormancyTrackingActiveParamName, element);
|
||||
|
||||
if (null != isDormancyActive && isDormancyActive) {
|
||||
final Long daysToInact = this.fromApiJsonHelper.extractLongNamed(daysToInactiveParamName, element);
|
||||
baseDataValidator.reset().parameter(daysToInactiveParamName).value(daysToInact).notNull().longGreaterThanZero();
|
||||
|
||||
final Long daysToDor = this.fromApiJsonHelper.extractLongNamed(daysToDormancyParamName, element);
|
||||
baseDataValidator.reset().parameter(daysToDormancyParamName).value(daysToDor).notNull().longGreaterThanZero();
|
||||
|
||||
final Long daysToEsc = this.fromApiJsonHelper.extractLongNamed(daysToEscheatParamName, element);
|
||||
baseDataValidator.reset().parameter(daysToEscheatParamName).value(daysToEsc).notNull().longGreaterThanZero();
|
||||
|
||||
if (null != daysToInact && null != daysToDor && null != daysToEsc) {
|
||||
baseDataValidator.reset().parameter(daysToDormancyParamName).value(daysToDor).longGreaterThanNumber(daysToInact);
|
||||
baseDataValidator.reset().parameter(daysToEscheatParamName).value(daysToEsc).longGreaterThanNumber(daysToDor);
|
||||
}
|
||||
}
|
||||
|
||||
// accounting related data validation
|
||||
final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 3);
|
||||
|
||||
if (isCashBasedAccounting(accountingRuleType)) {
|
||||
|
||||
final Long savingsControlAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_CONTROL.getValue()).value(savingsControlAccountId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long savingsReferenceAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue()).value(savingsReferenceAccountId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long transfersInSuspenseAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue())
|
||||
.value(transfersInSuspenseAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long interestOnSavingsAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue())
|
||||
.value(interestOnSavingsAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromFeeId = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_FEES.getValue(),
|
||||
element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId).notNull()
|
||||
.integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromPenaltyId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue()).value(incomeFromPenaltyId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long overdraftControlAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue())
|
||||
.value(overdraftControlAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromInterest = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue()).value(incomeFromInterest)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long writtenoff = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(),
|
||||
element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue()).value(writtenoff).notNull()
|
||||
.integerGreaterThanZero();
|
||||
|
||||
if (null != isDormancyActive && isDormancyActive) {
|
||||
final Long escheatLiabilityAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue())
|
||||
.value(escheatLiabilityAccountId).notNull().integerGreaterThanZero();
|
||||
}
|
||||
|
||||
validatePaymentChannelFundSourceMappings(baseDataValidator, element);
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element);
|
||||
}
|
||||
|
||||
validateOverdraftParams(baseDataValidator, element);
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(minBalanceForInterestCalculationParamName, element)) {
|
||||
final BigDecimal minBalanceForInterestCalculation = this.fromApiJsonHelper
|
||||
.extractBigDecimalWithLocaleNamed(minBalanceForInterestCalculationParamName, element);
|
||||
baseDataValidator.reset().parameter(minBalanceForInterestCalculationParamName).value(minBalanceForInterestCalculation)
|
||||
.ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
validateTaxWithHoldingParams(baseDataValidator, element, true);
|
||||
validateLienParams(baseDataValidator, element);
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
public void validateForUpdate(final String json, final SavingsProduct product) {
|
||||
|
||||
if (StringUtils.isBlank(json)) {
|
||||
throw new InvalidJsonException();
|
||||
}
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_PRODUCT_RESOURCE_NAME);
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(nameParamName, element)) {
|
||||
final String name = this.fromApiJsonHelper.extractStringNamed(nameParamName, element);
|
||||
baseDataValidator.reset().parameter(nameParamName).value(name).notBlank().notExceedingLengthOf(100);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(shortNameParamName, element)) {
|
||||
final String shortName = this.fromApiJsonHelper.extractStringNamed(shortNameParamName, element);
|
||||
baseDataValidator.reset().parameter(shortNameParamName).value(shortName).notBlank().notExceedingLengthOf(4);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(descriptionParamName, element)) {
|
||||
final String description = this.fromApiJsonHelper.extractStringNamed(descriptionParamName, element);
|
||||
baseDataValidator.reset().parameter(descriptionParamName).value(description).notBlank().notExceedingLengthOf(500);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(currencyCodeParamName, element)) {
|
||||
final String currencyCode = this.fromApiJsonHelper.extractStringNamed(currencyCodeParamName, element);
|
||||
baseDataValidator.reset().parameter(currencyCodeParamName).value(currencyCode).notBlank();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(digitsAfterDecimalParamName, element)) {
|
||||
final Integer digitsAfterDecimal = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(digitsAfterDecimalParamName, element);
|
||||
baseDataValidator.reset().parameter(digitsAfterDecimalParamName).value(digitsAfterDecimal).notNull().inMinMaxRange(0, 6);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(inMultiplesOfParamName, element)) {
|
||||
final Integer inMultiplesOf = this.fromApiJsonHelper.extractIntegerNamed(inMultiplesOfParamName, element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter(inMultiplesOfParamName).value(inMultiplesOf).ignoreIfNull().integerZeroOrGreater();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(nominalAnnualInterestRateParamName, element)) {
|
||||
final BigDecimal interestRate = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(nominalAnnualInterestRateParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(nominalAnnualInterestRateParamName).value(interestRate).notNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(interestCompoundingPeriodTypeParamName, element)) {
|
||||
final Integer interestCompoundingPeriodType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(interestCompoundingPeriodTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(interestCompoundingPeriodTypeParamName).value(interestCompoundingPeriodType).notNull()
|
||||
.isOneOfTheseValues(SavingsCompoundingInterestPeriodType.integerValues());
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(interestCalculationTypeParamName, element)) {
|
||||
final Integer interestCalculationType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(interestCalculationTypeParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(interestCalculationTypeParamName).value(interestCalculationType).notNull().inMinMaxRange(1,
|
||||
2);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(interestCalculationDaysInYearTypeParamName, element)) {
|
||||
final Integer interestCalculationDaysInYearType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(interestCalculationDaysInYearTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(interestCalculationDaysInYearTypeParamName).value(interestCalculationDaysInYearType)
|
||||
.notNull().isOneOfTheseValues(360, 365);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(minRequiredOpeningBalanceParamName, element)) {
|
||||
final BigDecimal minOpeningBalance = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minRequiredOpeningBalanceParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(minRequiredOpeningBalanceParamName).value(minOpeningBalance).ignoreIfNull()
|
||||
.zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyParamName, element)) {
|
||||
final Integer lockinPeriodFrequency = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(lockinPeriodFrequencyParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).ignoreIfNull()
|
||||
.integerZeroOrGreater();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyTypeParamName, element)) {
|
||||
final Integer lockinPeriodFrequencyType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(lockinPeriodFrequencyTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).inMinMaxRange(0, 3);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeForTransfersParamName, element)) {
|
||||
final Boolean isWithdrawalFeeApplicableForTransfers = this.fromApiJsonHelper
|
||||
.extractBooleanNamed(withdrawalFeeForTransfersParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeForTransfersParamName).value(isWithdrawalFeeApplicableForTransfers)
|
||||
.ignoreIfNull().validateForBooleanValue();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(feeAmountParamName, element)) {
|
||||
final BigDecimal annualFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(feeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(feeAmountParamName).value(annualFeeAmount).ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(feeOnMonthDayParamName, element)) {
|
||||
final MonthDay monthDayOfAnnualFee = this.fromApiJsonHelper.extractMonthDayNamed(feeOnMonthDayParamName, element);
|
||||
baseDataValidator.reset().parameter(feeOnMonthDayParamName).value(monthDayOfAnnualFee).ignoreIfNull();
|
||||
}
|
||||
|
||||
final Long savingsControlAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_CONTROL.getValue()).value(savingsControlAccountId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long savingsReferenceAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue()).value(savingsReferenceAccountId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long transfersInSuspenseAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue()).value(transfersInSuspenseAccountId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long interestOnSavingsAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue()).value(interestOnSavingsAccountId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromFeeId = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_FEES.getValue(),
|
||||
element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId).ignoreIfNull()
|
||||
.integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromPenaltyId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue()).value(incomeFromPenaltyId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long overdraftAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue()).value(overdraftAccountId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromInterest = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue()).value(incomeFromInterest)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long writtenoff = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(),
|
||||
element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue()).value(writtenoff).ignoreIfNull()
|
||||
.integerGreaterThanZero();
|
||||
|
||||
// dormancy
|
||||
final Boolean isDormancyActive = this.fromApiJsonHelper.parameterExists(isDormancyTrackingActiveParamName, element)
|
||||
? this.fromApiJsonHelper.extractBooleanNamed(isDormancyTrackingActiveParamName, element)
|
||||
: product.isDormancyTrackingActive();
|
||||
|
||||
if (null != isDormancyActive && isDormancyActive) {
|
||||
final Long daysToInact = this.fromApiJsonHelper.parameterExists(daysToInactiveParamName, element)
|
||||
? this.fromApiJsonHelper.extractLongNamed(daysToInactiveParamName, element)
|
||||
: product.getDaysToInactive();
|
||||
baseDataValidator.reset().parameter(daysToInactiveParamName).value(daysToInact).notNull().longGreaterThanZero();
|
||||
|
||||
final Long daysToDor = this.fromApiJsonHelper.parameterExists(daysToDormancyParamName, element)
|
||||
? this.fromApiJsonHelper.extractLongNamed(daysToDormancyParamName, element)
|
||||
: product.getDaysToDormancy();
|
||||
baseDataValidator.reset().parameter(daysToDormancyParamName).value(daysToDor).notNull().longGreaterThanZero();
|
||||
|
||||
final Long daysToEsc = this.fromApiJsonHelper.parameterExists(daysToEscheatParamName, element)
|
||||
? this.fromApiJsonHelper.extractLongNamed(daysToEscheatParamName, element)
|
||||
: product.getDaysToEscheat();
|
||||
baseDataValidator.reset().parameter(daysToEscheatParamName).value(daysToEsc).notNull().longGreaterThanZero();
|
||||
|
||||
if (null != daysToInact && null != daysToDor && null != daysToEsc) {
|
||||
baseDataValidator.reset().parameter(daysToDormancyParamName).value(daysToDor).longGreaterThanNumber(daysToInact);
|
||||
baseDataValidator.reset().parameter(daysToEscheatParamName).value(daysToEsc).longGreaterThanNumber(daysToDor);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue(), element)) {
|
||||
final Long escheatLiabilityAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue())
|
||||
.value(escheatLiabilityAccountId).notNull().integerGreaterThanZero();
|
||||
}
|
||||
}
|
||||
|
||||
validatePaymentChannelFundSourceMappings(baseDataValidator, element);
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element);
|
||||
validateOverdraftParams(baseDataValidator, element);
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(minBalanceForInterestCalculationParamName, element)) {
|
||||
final BigDecimal minBalanceForInterestCalculation = this.fromApiJsonHelper
|
||||
.extractBigDecimalWithLocaleNamed(minBalanceForInterestCalculationParamName, element);
|
||||
baseDataValidator.reset().parameter(minBalanceForInterestCalculationParamName).value(minBalanceForInterestCalculation)
|
||||
.ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
validateTaxWithHoldingParams(baseDataValidator, element, false);
|
||||
validateLienParams(baseDataValidator, element);
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCashBasedAccounting(final Integer accountingRuleType) {
|
||||
return AccountingRuleType.CASH_BASED.getValue().equals(accountingRuleType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation for advanced accounting options
|
||||
*/
|
||||
private void validatePaymentChannelFundSourceMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
||||
if (this.fromApiJsonHelper.parameterExists(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element)) {
|
||||
final JsonArray paymentChannelMappingArray = this.fromApiJsonHelper
|
||||
.extractJsonArrayNamed(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element);
|
||||
if (paymentChannelMappingArray != null && paymentChannelMappingArray.size() > 0) {
|
||||
int i = 0;
|
||||
do {
|
||||
final JsonObject jsonObject = paymentChannelMappingArray.get(i).getAsJsonObject();
|
||||
final Long paymentTypeId = jsonObject.get(SavingProductAccountingParams.PAYMENT_TYPE.getValue()).getAsLong();
|
||||
final Long paymentSpecificFundAccountId = jsonObject.get(SavingProductAccountingParams.FUND_SOURCE.getValue())
|
||||
.getAsLong();
|
||||
baseDataValidator.reset()
|
||||
.parameter(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
|
||||
+ SavingProductAccountingParams.PAYMENT_TYPE.toString())
|
||||
.value(paymentTypeId).notNull().integerGreaterThanZero();
|
||||
baseDataValidator.reset()
|
||||
.parameter(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
|
||||
+ SavingProductAccountingParams.FUND_SOURCE.getValue())
|
||||
.value(paymentSpecificFundAccountId).notNull().integerGreaterThanZero();
|
||||
i++;
|
||||
} while (i < paymentChannelMappingArray.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateChargeToIncomeAccountMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
||||
// validate for both fee and penalty charges
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element, true);
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element, true);
|
||||
}
|
||||
|
||||
private void validateChargeToIncomeAccountMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element,
|
||||
final boolean isPenalty) {
|
||||
String parameterName;
|
||||
if (isPenalty) {
|
||||
parameterName = SavingProductAccountingParams.PENALTY_INCOME_ACCOUNT_MAPPING.getValue();
|
||||
} else {
|
||||
parameterName = SavingProductAccountingParams.FEE_INCOME_ACCOUNT_MAPPING.getValue();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(parameterName, element)) {
|
||||
final JsonArray chargeToIncomeAccountMappingArray = this.fromApiJsonHelper.extractJsonArrayNamed(parameterName, element);
|
||||
if (chargeToIncomeAccountMappingArray != null && chargeToIncomeAccountMappingArray.size() > 0) {
|
||||
int i = 0;
|
||||
do {
|
||||
final JsonObject jsonObject = chargeToIncomeAccountMappingArray.get(i).getAsJsonObject();
|
||||
final Long chargeId = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.CHARGE_ID.getValue(),
|
||||
jsonObject);
|
||||
final Long incomeAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INCOME_ACCOUNT_ID.getValue(), jsonObject);
|
||||
baseDataValidator.reset().parameter(parameterName + "[" + i + "]." + SavingProductAccountingParams.CHARGE_ID.getValue())
|
||||
.value(chargeId).notNull().integerGreaterThanZero();
|
||||
baseDataValidator.reset()
|
||||
.parameter(parameterName + "[" + i + "]." + SavingProductAccountingParams.INCOME_ACCOUNT_ID.getValue())
|
||||
.value(incomeAccountId).notNull().integerGreaterThanZero();
|
||||
i++;
|
||||
} while (i < chargeToIncomeAccountMappingArray.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateOverdraftParams(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
||||
if (this.fromApiJsonHelper.parameterExists(allowOverdraftParamName, element)) {
|
||||
final Boolean allowOverdraft = this.fromApiJsonHelper.extractBooleanNamed(allowOverdraftParamName, element);
|
||||
baseDataValidator.reset().parameter(allowOverdraftParamName).value(allowOverdraft).ignoreIfNull().validateForBooleanValue();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(overdraftLimitParamName, element)) {
|
||||
final BigDecimal overdraftLimit = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(overdraftLimitParamName, element);
|
||||
baseDataValidator.reset().parameter(overdraftLimitParamName).value(overdraftLimit).ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(nominalAnnualInterestRateOverdraftParamName, element)) {
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft = this.fromApiJsonHelper
|
||||
.extractBigDecimalWithLocaleNamed(nominalAnnualInterestRateOverdraftParamName, element);
|
||||
baseDataValidator.reset().parameter(nominalAnnualInterestRateOverdraftParamName).value(nominalAnnualInterestRateOverdraft)
|
||||
.ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(minOverdraftForInterestCalculationParamName, element)) {
|
||||
final BigDecimal minOverdraftForInterestCalculation = this.fromApiJsonHelper
|
||||
.extractBigDecimalWithLocaleNamed(minOverdraftForInterestCalculationParamName, element);
|
||||
baseDataValidator.reset().parameter(minOverdraftForInterestCalculationParamName).value(minOverdraftForInterestCalculation)
|
||||
.ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void validateLienParams(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
||||
if (this.fromApiJsonHelper.parameterExists(lienAllowedParamName, element)) {
|
||||
final Boolean lienAllowed = this.fromApiJsonHelper.extractBooleanNamed(lienAllowedParamName, element);
|
||||
baseDataValidator.reset().parameter(lienAllowedParamName).value(lienAllowed).ignoreIfNull().validateForBooleanValue();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(maxAllowedLienLimitParamName, element)) {
|
||||
final BigDecimal maxAllowedLienLimit = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxAllowedLienLimitParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(maxAllowedLienLimitParamName).value(maxAllowedLienLimit).ignoreIfNull()
|
||||
.zeroOrPositiveAmount();
|
||||
}
|
||||
if (BooleanUtils.isTrue(this.fromApiJsonHelper.extractBooleanNamed(lienAllowedParamName, element))
|
||||
&& BooleanUtils.isTrue(this.fromApiJsonHelper.extractBooleanNamed(allowOverdraftParamName, element))) {
|
||||
final BigDecimal maxAllowedLienLimit = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxAllowedLienLimitParamName,
|
||||
element);
|
||||
final BigDecimal overdraftLimit = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(overdraftLimitParamName, element);
|
||||
if (overdraftLimit.compareTo(maxAllowedLienLimit) > 0) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("Overdraft.limit.can.not.be.greater.than.lien.limit");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateTaxWithHoldingParams(final DataValidatorBuilder baseDataValidator, final JsonElement element,
|
||||
final boolean isCreate) {
|
||||
if (this.fromApiJsonHelper.parameterExists(withHoldTaxParamName, element)) {
|
||||
final String withHoldTax = this.fromApiJsonHelper.extractStringNamed(withHoldTaxParamName, element);
|
||||
baseDataValidator.reset().parameter(withHoldTaxParamName).value(withHoldTax).ignoreIfNull().validateForBooleanValue();
|
||||
}
|
||||
Boolean withHoldTax = this.fromApiJsonHelper.extractBooleanNamed(withHoldTaxParamName, element);
|
||||
if (withHoldTax == null) {
|
||||
withHoldTax = false;
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(taxGroupIdParamName, element)) {
|
||||
final Long taxGroupId = this.fromApiJsonHelper.extractLongNamed(taxGroupIdParamName, element);
|
||||
baseDataValidator.reset().parameter(taxGroupIdParamName).value(taxGroupId).ignoreIfNull().longGreaterThanZero();
|
||||
if (withHoldTax) {
|
||||
baseDataValidator.reset().parameter(taxGroupIdParamName).value(taxGroupId).notBlank();
|
||||
}
|
||||
|
||||
} else if (withHoldTax && isCreate) {
|
||||
final Long taxGroupId = null;
|
||||
baseDataValidator.reset().parameter(taxGroupIdParamName).value(taxGroupId).notBlank();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+34
@@ -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.savings.data;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* Immutable data object representing date
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class TransactionDateData {
|
||||
|
||||
private final LocalDate date;
|
||||
|
||||
public TransactionDateData(final LocalDate date) {
|
||||
this.date = date;
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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 jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestIncentivesFields;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_deposit_account_interest_incentives")
|
||||
public class DepositAccountInterestIncentive extends AbstractPersistableCustom {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "deposit_account_interest_rate_slab_id", nullable = false)
|
||||
private DepositAccountInterestRateChartSlabs depositAccountInterestRateChartSlabs;
|
||||
|
||||
@Embedded
|
||||
private InterestIncentivesFields interestIncentivesFields;
|
||||
|
||||
protected DepositAccountInterestIncentive() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public DepositAccountInterestIncentive(final DepositAccountInterestRateChartSlabs depositAccountInterestRateChartSlabs,
|
||||
final InterestIncentivesFields interestIncentivesFields) {
|
||||
this.depositAccountInterestRateChartSlabs = depositAccountInterestRateChartSlabs;
|
||||
this.interestIncentivesFields = interestIncentivesFields;
|
||||
}
|
||||
|
||||
}
|
||||
+63
@@ -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.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestIncentivesFields;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_savings_interest_incentives")
|
||||
public class DepositAccountInterestIncentives extends AbstractPersistableCustom {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "deposit_account_interest_rate_slab_id", nullable = false)
|
||||
private DepositAccountInterestRateChartSlabs depositAccountInterestRateChartSlabs;
|
||||
|
||||
@Embedded
|
||||
private InterestIncentivesFields interestIncentivesFields;
|
||||
|
||||
protected DepositAccountInterestIncentives() {
|
||||
|
||||
}
|
||||
|
||||
private DepositAccountInterestIncentives(final DepositAccountInterestRateChartSlabs depositAccountInterestRateChartSlabs,
|
||||
final InterestIncentivesFields interestIncentivesFields) {
|
||||
this.depositAccountInterestRateChartSlabs = depositAccountInterestRateChartSlabs;
|
||||
this.interestIncentivesFields = interestIncentivesFields;
|
||||
}
|
||||
|
||||
public static DepositAccountInterestIncentives from(final DepositAccountInterestRateChartSlabs depositAccountInterestRateChartSlabs,
|
||||
final InterestIncentivesFields interestIncentivesFields) {
|
||||
return new DepositAccountInterestIncentives(depositAccountInterestRateChartSlabs, interestIncentivesFields);
|
||||
}
|
||||
|
||||
public void updateDepositAccountInterestRateChartSlabs(DepositAccountInterestRateChartSlabs depositAccountInterestRateChartSlabs) {
|
||||
this.depositAccountInterestRateChartSlabs = depositAccountInterestRateChartSlabs;
|
||||
}
|
||||
|
||||
public InterestIncentivesFields interestIncentivesFields() {
|
||||
return this.interestIncentivesFields;
|
||||
}
|
||||
|
||||
}
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* 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 jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestRateChart;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestRateChartFields;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestRateChartSlab;
|
||||
import org.apache.fineract.portfolio.interestratechart.incentive.AttributeIncentiveCalculation;
|
||||
import org.apache.fineract.portfolio.interestratechart.incentive.AttributeIncentiveCalculationFactory;
|
||||
import org.apache.fineract.portfolio.interestratechart.incentive.IncentiveDTO;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_savings_account_interest_rate_chart")
|
||||
public class DepositAccountInterestRateChart extends AbstractPersistableCustom {
|
||||
|
||||
@Embedded
|
||||
private InterestRateChartFields chartFields;
|
||||
|
||||
@OneToOne
|
||||
@JoinColumn(name = "savings_account_id", nullable = false)
|
||||
private SavingsAccount account;
|
||||
|
||||
@OneToMany(mappedBy = "depositAccountInterestRateChart", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private Set<DepositAccountInterestRateChartSlabs> chartSlabs = new HashSet<>();
|
||||
|
||||
protected DepositAccountInterestRateChart() {
|
||||
//
|
||||
}
|
||||
|
||||
public static DepositAccountInterestRateChart from(InterestRateChart productChart) {
|
||||
final Set<InterestRateChartSlab> chartSlabs = productChart.setOfChartSlabs();
|
||||
final Set<DepositAccountInterestRateChartSlabs> depostiChartSlabs = new HashSet<>();
|
||||
for (InterestRateChartSlab interestRateChartSlab : chartSlabs) {
|
||||
depostiChartSlabs.add(DepositAccountInterestRateChartSlabs.from(interestRateChartSlab, null));
|
||||
}
|
||||
final DepositAccountInterestRateChart depositChart = new DepositAccountInterestRateChart(productChart.chartFields(), null,
|
||||
depostiChartSlabs);
|
||||
// update deposit account interest rate chart ference to chart Slabs
|
||||
depositChart.updateChartSlabsReference();
|
||||
return depositChart;
|
||||
}
|
||||
|
||||
private DepositAccountInterestRateChart(InterestRateChartFields chartFields, SavingsAccount account,
|
||||
Set<DepositAccountInterestRateChartSlabs> chartSlabs) {
|
||||
this.chartFields = chartFields;
|
||||
this.account = account;
|
||||
this.chartSlabs = chartSlabs;
|
||||
}
|
||||
|
||||
private void updateChartSlabsReference() {
|
||||
final Set<DepositAccountInterestRateChartSlabs> chartSlabs = setOfChartSlabs();
|
||||
for (DepositAccountInterestRateChartSlabs chartSlab : chartSlabs) {
|
||||
chartSlab.updateChartReference(this);
|
||||
}
|
||||
}
|
||||
|
||||
public Set<DepositAccountInterestRateChartSlabs> setOfChartSlabs() {
|
||||
if (this.chartSlabs == null) {
|
||||
this.chartSlabs = new HashSet<>();
|
||||
}
|
||||
|
||||
return this.chartSlabs;
|
||||
}
|
||||
|
||||
public DepositAccountInterestRateChartSlabs findChartSlab(Long chartSlabId) {
|
||||
final Set<DepositAccountInterestRateChartSlabs> chartSlabs = setOfChartSlabs();
|
||||
|
||||
for (DepositAccountInterestRateChartSlabs interestRateChartSlab : chartSlabs) {
|
||||
if (interestRateChartSlab.getId().equals(chartSlabId)) {
|
||||
return interestRateChartSlab;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public LocalDate getFromDate() {
|
||||
return this.chartFields.getFromDate();
|
||||
}
|
||||
|
||||
public LocalDate getEndDate() {
|
||||
return this.chartFields.getEndDate();
|
||||
}
|
||||
|
||||
public Long savingsAccountId() {
|
||||
return this.account == null ? null : this.account.getId();
|
||||
}
|
||||
|
||||
public SavingsAccount savingsAccount() {
|
||||
return this.account;
|
||||
}
|
||||
|
||||
public InterestRateChartFields chartFields() {
|
||||
return this.chartFields;
|
||||
}
|
||||
|
||||
public void updateDepositAccountReference(final SavingsAccount account) {
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
public BigDecimal getApplicableInterestRate(final BigDecimal depositAmount, final LocalDate periodStartDate,
|
||||
final LocalDate periodEndDate, final Client client) {
|
||||
BigDecimal effectiveInterestRate = BigDecimal.ZERO;
|
||||
for (DepositAccountInterestRateChartSlabs slab : setOfChartSlabs()) {
|
||||
if (slab.slabFields().isBetweenPeriod(periodStartDate, periodEndDate) && slab.slabFields().isAmountBetween(depositAmount)) {
|
||||
|
||||
effectiveInterestRate = slab.slabFields().annualInterestRate();
|
||||
Set<DepositAccountInterestIncentives> depositInterestIncentives = slab.setOfIncentives();
|
||||
for (DepositAccountInterestIncentives incentives : depositInterestIncentives) {
|
||||
AttributeIncentiveCalculation attributeIncentiveCalculation = AttributeIncentiveCalculationFactory
|
||||
.findAttributeIncentiveCalculation(incentives.interestIncentivesFields().entiryType());
|
||||
IncentiveDTO incentiveDTO = new IncentiveDTO(client, effectiveInterestRate, incentives.interestIncentivesFields());
|
||||
effectiveInterestRate = attributeIncentiveCalculation.calculateIncentive(incentiveDTO);
|
||||
}
|
||||
|
||||
// effectiveInterestRate is zero or null then reset to default
|
||||
// interest rate.
|
||||
if (effectiveInterestRate == null || effectiveInterestRate.compareTo(BigDecimal.ZERO) == 0) {
|
||||
effectiveInterestRate = slab.slabFields().annualInterestRate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return effectiveInterestRate;
|
||||
}
|
||||
|
||||
public boolean isPrimaryGroupingByAmount() {
|
||||
return this.chartFields.isPrimaryGroupingByAmount();
|
||||
}
|
||||
}
|
||||
+105
@@ -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.savings.domain;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestIncentives;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestRateChartSlab;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestRateChartSlabFields;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_savings_account_interest_rate_slab")
|
||||
public class DepositAccountInterestRateChartSlabs extends AbstractPersistableCustom {
|
||||
|
||||
@Embedded
|
||||
private InterestRateChartSlabFields slabFields;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "savings_account_interest_rate_chart_id", referencedColumnName = "id", nullable = false)
|
||||
private DepositAccountInterestRateChart depositAccountInterestRateChart;
|
||||
|
||||
@OneToMany(mappedBy = "depositAccountInterestRateChartSlabs", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private Set<DepositAccountInterestIncentives> interestIncentives = new HashSet<>();
|
||||
|
||||
protected DepositAccountInterestRateChartSlabs() {
|
||||
//
|
||||
}
|
||||
|
||||
private DepositAccountInterestRateChartSlabs(InterestRateChartSlabFields slabFields,
|
||||
DepositAccountInterestRateChart depositAccountInterestRateChart,
|
||||
final Set<DepositAccountInterestIncentives> interestIncentives) {
|
||||
this.slabFields = slabFields;
|
||||
this.depositAccountInterestRateChart = depositAccountInterestRateChart;
|
||||
this.interestIncentives = interestIncentives;
|
||||
}
|
||||
|
||||
public void setDepositAccountInterestRateChart(DepositAccountInterestRateChart depositAccountInterestRateChart) {
|
||||
this.depositAccountInterestRateChart = depositAccountInterestRateChart;
|
||||
}
|
||||
|
||||
public Long savingsProductId() {
|
||||
return this.depositAccountInterestRateChart.savingsAccountId();
|
||||
}
|
||||
|
||||
public InterestRateChartSlabFields slabFields() {
|
||||
return this.slabFields;
|
||||
}
|
||||
|
||||
public static DepositAccountInterestRateChartSlabs from(InterestRateChartSlab interestRateChartSlab,
|
||||
DepositAccountInterestRateChart depositAccountInterestRateChart) {
|
||||
InterestRateChartSlabFields slabFields = interestRateChartSlab.slabFields();
|
||||
Set<DepositAccountInterestIncentives> depositInterestIncentives = new HashSet<>();
|
||||
Set<InterestIncentives> incentives = interestRateChartSlab.setOfInterestIncentives();
|
||||
for (InterestIncentives incentive : incentives) {
|
||||
depositInterestIncentives.add(DepositAccountInterestIncentives.from(null, incentive.interestIncentivesFields()));
|
||||
}
|
||||
DepositAccountInterestRateChartSlabs chartSlabs = new DepositAccountInterestRateChartSlabs(slabFields,
|
||||
depositAccountInterestRateChart, depositInterestIncentives);
|
||||
chartSlabs.updateIncentiveReference();
|
||||
return chartSlabs;
|
||||
}
|
||||
|
||||
private void updateIncentiveReference() {
|
||||
final Set<DepositAccountInterestIncentives> incentives = setOfIncentives();
|
||||
for (DepositAccountInterestIncentives depositInterestIncentives : incentives) {
|
||||
depositInterestIncentives.updateDepositAccountInterestRateChartSlabs(this);
|
||||
}
|
||||
}
|
||||
|
||||
public Set<DepositAccountInterestIncentives> setOfIncentives() {
|
||||
if (this.interestIncentives == null) {
|
||||
this.interestIncentives = new HashSet<>();
|
||||
}
|
||||
return this.interestIncentives;
|
||||
}
|
||||
|
||||
public void updateChartReference(final DepositAccountInterestRateChart chart) {
|
||||
this.depositAccountInterestRateChart = chart;
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* 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 static org.apache.fineract.infrastructure.core.service.DateUtils.getSystemZoneId;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Optional;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.savings.DepositAccountOnHoldTransactionType;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_deposit_account_on_hold_transaction")
|
||||
public class DepositAccountOnHoldTransaction extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "savings_account_id", nullable = true)
|
||||
private SavingsAccount savingsAccount;
|
||||
|
||||
@Column(name = "amount", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal amount;
|
||||
|
||||
@Column(name = "transaction_type_enum", nullable = false)
|
||||
private Integer transactionType;
|
||||
|
||||
@Column(name = "transaction_date", nullable = false)
|
||||
private LocalDate transactionDate;
|
||||
|
||||
@Column(name = "is_reversed", nullable = false)
|
||||
private boolean reversed;
|
||||
|
||||
@Deprecated
|
||||
@Column(name = "created_date", nullable = true)
|
||||
private LocalDateTime createdDateToRemove;
|
||||
|
||||
protected DepositAccountOnHoldTransaction() {}
|
||||
|
||||
private DepositAccountOnHoldTransaction(final SavingsAccount savingsAccount, final BigDecimal amount,
|
||||
final DepositAccountOnHoldTransactionType transactionType, final LocalDate transactionDate, final boolean reversed) {
|
||||
this.savingsAccount = savingsAccount;
|
||||
this.amount = amount;
|
||||
this.transactionType = transactionType.getValue();
|
||||
this.transactionDate = transactionDate;
|
||||
this.createdDateToRemove = null; // #audit backward compatibility deprecated
|
||||
this.reversed = reversed;
|
||||
}
|
||||
|
||||
public static DepositAccountOnHoldTransaction hold(final SavingsAccount savingsAccount, final BigDecimal amount,
|
||||
final LocalDate transactionDate) {
|
||||
boolean reversed = false;
|
||||
return new DepositAccountOnHoldTransaction(savingsAccount, amount, DepositAccountOnHoldTransactionType.HOLD, transactionDate,
|
||||
reversed);
|
||||
}
|
||||
|
||||
public static DepositAccountOnHoldTransaction release(final SavingsAccount savingsAccount, final BigDecimal amount,
|
||||
final LocalDate transactionDate) {
|
||||
boolean reversed = false;
|
||||
return new DepositAccountOnHoldTransaction(savingsAccount, amount, DepositAccountOnHoldTransactionType.RELEASE, transactionDate,
|
||||
reversed);
|
||||
}
|
||||
|
||||
public SavingsAccount getSavingsAccount() {
|
||||
return savingsAccount;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public Money getAmount(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amount);
|
||||
}
|
||||
|
||||
public DepositAccountOnHoldTransactionType getTransactionType() {
|
||||
return DepositAccountOnHoldTransactionType.fromInt(this.transactionType);
|
||||
}
|
||||
|
||||
public LocalDate getTransactionDate() {
|
||||
return this.transactionDate;
|
||||
}
|
||||
|
||||
public MonetaryCurrency getCurrency() {
|
||||
return getSavingsAccount().getCurrency();
|
||||
}
|
||||
|
||||
public void reverseTransaction() {
|
||||
this.reversed = true;
|
||||
if (this.getTransactionType().isHold()) {
|
||||
this.savingsAccount.releaseFunds(this.amount);
|
||||
} else {
|
||||
this.savingsAccount.holdFunds(this.amount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<OffsetDateTime> getCreatedDate() {
|
||||
// #audit backward compatibility keep system datetime
|
||||
return Optional.ofNullable(super.getCreatedDate()
|
||||
.orElse(createdDateToRemove == null ? null : createdDateToRemove.atZone(getSystemZoneId()).toOffsetDateTime()));
|
||||
}
|
||||
}
|
||||
+329
@@ -0,0 +1,329 @@
|
||||
/**
|
||||
* 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 static org.apache.fineract.portfolio.savings.DepositsApiConstants.dateFormatParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.depositAmountParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.depositPeriodFrequencyIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.depositPeriodParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.expectedFirstDepositOnDateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.localeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.maturityInstructionIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.transferInterestToSavingsParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.transferToSavingsIdParamName;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.portfolio.savings.DepositAccountOnClosureType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
import org.apache.fineract.portfolio.savings.service.SavingsEnumerations;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_deposit_account_term_and_preclosure")
|
||||
public class DepositAccountTermAndPreClosure extends AbstractPersistableCustom {
|
||||
|
||||
@Column(name = "deposit_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal depositAmount;
|
||||
|
||||
@Column(name = "maturity_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal maturityAmount;
|
||||
|
||||
@Column(name = "maturity_date", nullable = true)
|
||||
private LocalDate maturityDate;
|
||||
|
||||
@Column(name = "expected_firstdepositon_date")
|
||||
private LocalDate expectedFirstDepositOnDate;
|
||||
|
||||
@Column(name = "deposit_period", nullable = true)
|
||||
private Integer depositPeriod;
|
||||
|
||||
@Column(name = "deposit_period_frequency_enum", nullable = true)
|
||||
private Integer depositPeriodFrequency;
|
||||
|
||||
@Column(name = "on_account_closure_enum", nullable = true)
|
||||
private Integer onAccountClosureType;
|
||||
|
||||
@Embedded
|
||||
private DepositPreClosureDetail preClosureDetail;
|
||||
|
||||
@Embedded
|
||||
protected DepositTermDetail depositTermDetail;
|
||||
|
||||
@OneToOne
|
||||
@JoinColumn(name = "savings_account_id", nullable = false)
|
||||
private SavingsAccount account;
|
||||
|
||||
@Column(name = "transfer_interest_to_linked_account", nullable = false)
|
||||
private boolean transferInterestToLinkedAccount;
|
||||
|
||||
@Column(name = "transfer_to_savings_account_id")
|
||||
private Long transferToSavingsAccountId;
|
||||
|
||||
protected DepositAccountTermAndPreClosure() {
|
||||
|
||||
}
|
||||
|
||||
public static DepositAccountTermAndPreClosure createNew(DepositPreClosureDetail preClosureDetail, DepositTermDetail depositTermDetail,
|
||||
SavingsAccount account, BigDecimal depositAmount, BigDecimal maturityAmount, final LocalDate maturityDate,
|
||||
Integer depositPeriod, final SavingsPeriodFrequencyType depositPeriodFrequency, final LocalDate expectedFirstDepositOnDate,
|
||||
final DepositAccountOnClosureType accountOnClosureType, Boolean trasferInterest, Long transferToSavingsId) {
|
||||
|
||||
return new DepositAccountTermAndPreClosure(preClosureDetail, depositTermDetail, account, depositAmount, maturityAmount,
|
||||
maturityDate, depositPeriod, depositPeriodFrequency, expectedFirstDepositOnDate, accountOnClosureType, trasferInterest,
|
||||
transferToSavingsId);
|
||||
}
|
||||
|
||||
private DepositAccountTermAndPreClosure(DepositPreClosureDetail preClosureDetail, DepositTermDetail depositTermDetail,
|
||||
SavingsAccount account, BigDecimal depositAmount, BigDecimal maturityAmount, final LocalDate maturityDate,
|
||||
Integer depositPeriod, final SavingsPeriodFrequencyType depositPeriodFrequency, final LocalDate expectedFirstDepositOnDate,
|
||||
final DepositAccountOnClosureType accountOnClosureType, Boolean transferInterest, Long transferToSavingsId) {
|
||||
this.depositAmount = depositAmount;
|
||||
this.maturityAmount = maturityAmount;
|
||||
this.maturityDate = maturityDate;
|
||||
this.depositPeriod = depositPeriod;
|
||||
this.depositPeriodFrequency = (depositPeriodFrequency == null) ? null : depositPeriodFrequency.getValue();
|
||||
this.preClosureDetail = preClosureDetail;
|
||||
this.depositTermDetail = depositTermDetail;
|
||||
this.account = account;
|
||||
this.expectedFirstDepositOnDate = expectedFirstDepositOnDate;
|
||||
this.onAccountClosureType = (accountOnClosureType == null) ? null : accountOnClosureType.getValue();
|
||||
this.transferInterestToLinkedAccount = transferInterest;
|
||||
this.transferToSavingsAccountId = transferToSavingsId;
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command, final DataValidatorBuilder baseDataValidator) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(10);
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed(depositAmountParamName, this.depositAmount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(depositAmountParamName);
|
||||
actualChanges.put(depositAmountParamName, newValue);
|
||||
this.depositAmount = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(depositPeriodParamName, this.depositPeriod)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(depositPeriodParamName);
|
||||
actualChanges.put(depositPeriodParamName, newValue);
|
||||
this.depositPeriod = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(depositPeriodFrequencyIdParamName, this.depositPeriodFrequency)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(depositPeriodFrequencyIdParamName);
|
||||
actualChanges.put(depositPeriodFrequencyIdParamName, SavingsEnumerations.depositTermFrequencyType(newValue));
|
||||
this.depositPeriodFrequency = newValue;
|
||||
}
|
||||
|
||||
final String localeAsInput = command.locale();
|
||||
final String dateFormat = command.dateFormat();
|
||||
if (command.isChangeInLocalDateParameterNamed(expectedFirstDepositOnDateParamName, this.getExpectedFirstDepositOnDate())) {
|
||||
final String newValueAsString = command.stringValueOfParameterNamed(expectedFirstDepositOnDateParamName);
|
||||
actualChanges.put(expectedFirstDepositOnDateParamName, newValueAsString);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
actualChanges.put(dateFormatParamName, dateFormat);
|
||||
this.expectedFirstDepositOnDate = command.localDateValueOfParameterNamed(expectedFirstDepositOnDateParamName);
|
||||
}
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(transferInterestToSavingsParamName, this.transferInterestToLinkedAccount)) {
|
||||
final Boolean newValue = command.booleanPrimitiveValueOfParameterNamed(transferInterestToSavingsParamName);
|
||||
actualChanges.put(transferInterestToSavingsParamName, newValue);
|
||||
this.transferInterestToLinkedAccount = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(maturityInstructionIdParamName, this.onAccountClosureType)
|
||||
|| command.integerValueOfParameterNamed(maturityInstructionIdParamName) == null) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(maturityInstructionIdParamName);
|
||||
actualChanges.put(maturityInstructionIdParamName, newValue);
|
||||
this.onAccountClosureType = newValue != null ? DepositAccountOnClosureType.fromInt(newValue).getValue() : null;
|
||||
}
|
||||
|
||||
if (command.isChangeInLongParameterNamed(transferToSavingsIdParamName, this.transferToSavingsAccountId)
|
||||
|| command.integerValueOfParameterNamed(transferToSavingsIdParamName) == null) {
|
||||
final Long newValue = command.longValueOfParameterNamed(transferToSavingsIdParamName);
|
||||
actualChanges.put(transferToSavingsIdParamName, newValue);
|
||||
this.transferToSavingsAccountId = newValue;
|
||||
}
|
||||
|
||||
if (this.preClosureDetail != null) {
|
||||
actualChanges.putAll(this.preClosureDetail.update(command, baseDataValidator));
|
||||
}
|
||||
|
||||
if (this.depositTermDetail != null) {
|
||||
actualChanges.putAll(this.depositTermDetail.update(command, baseDataValidator));
|
||||
}
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public DepositPreClosureDetail depositPreClosureDetail() {
|
||||
return this.preClosureDetail;
|
||||
}
|
||||
|
||||
public DepositTermDetail depositTermDetail() {
|
||||
return this.depositTermDetail;
|
||||
}
|
||||
|
||||
public BigDecimal depositAmount() {
|
||||
return this.depositAmount;
|
||||
}
|
||||
|
||||
public Integer depositPeriod() {
|
||||
return this.depositPeriod;
|
||||
}
|
||||
|
||||
public Integer depositPeriodFrequency() {
|
||||
return this.depositPeriodFrequency;
|
||||
}
|
||||
|
||||
public SavingsPeriodFrequencyType depositPeriodFrequencyType() {
|
||||
return SavingsPeriodFrequencyType.fromInt(depositPeriodFrequency);
|
||||
}
|
||||
|
||||
public void updateAccountReference(final SavingsAccount account) {
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
public void updateMaturityDetails(final BigDecimal maturityAmount, final LocalDate maturityDate) {
|
||||
this.maturityAmount = maturityAmount;
|
||||
this.maturityDate = maturityDate;
|
||||
}
|
||||
|
||||
public void updateMaturityDetails(final BigDecimal depositAmount, final BigDecimal interestPayable, final LocalDate maturityDate) {
|
||||
this.depositAmount = depositAmount;
|
||||
this.maturityAmount = this.depositAmount.add(interestPayable);
|
||||
this.maturityDate = maturityDate;
|
||||
}
|
||||
|
||||
public void updateDepositAmount(final BigDecimal depositAmount) {
|
||||
this.depositAmount = depositAmount;
|
||||
}
|
||||
|
||||
public LocalDate getMaturityDate() {
|
||||
return this.maturityDate;
|
||||
}
|
||||
|
||||
public LocalDate getExpectedFirstDepositOnDate() {
|
||||
return this.expectedFirstDepositOnDate;
|
||||
}
|
||||
|
||||
public boolean isPreClosurePenalApplicable() {
|
||||
if (this.preClosureDetail != null) {
|
||||
return this.preClosureDetail.preClosurePenalApplicable();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Integer getActualDepositPeriod(final LocalDate interestPostingUpToDate, final SavingsPeriodFrequencyType periodFrequencyType) {
|
||||
LocalDate depositFromDate = getExpectedFirstDepositOnDate();
|
||||
|
||||
if (depositFromDate == null) {
|
||||
depositFromDate = this.account.accountSubmittedOrActivationDate();
|
||||
}
|
||||
|
||||
Integer actualDepositPeriod = this.depositPeriod;
|
||||
if (depositFromDate == null || getMaturityDate() == null || DateUtils.isEqual(interestPostingUpToDate, getMaturityDate())) {
|
||||
return actualDepositPeriod;
|
||||
}
|
||||
|
||||
final SavingsPeriodFrequencyType depositPeriodFrequencyType = periodFrequencyType;
|
||||
switch (depositPeriodFrequencyType) {
|
||||
case DAYS:
|
||||
actualDepositPeriod = Math.toIntExact(ChronoUnit.DAYS.between(depositFromDate, interestPostingUpToDate));
|
||||
break;
|
||||
case WEEKS:
|
||||
actualDepositPeriod = Math.toIntExact(ChronoUnit.WEEKS.between(depositFromDate, interestPostingUpToDate));
|
||||
break;
|
||||
case MONTHS:
|
||||
actualDepositPeriod = Math.toIntExact(ChronoUnit.MONTHS.between(depositFromDate, interestPostingUpToDate));
|
||||
break;
|
||||
case YEARS:
|
||||
actualDepositPeriod = Math.toIntExact(ChronoUnit.YEARS.between(depositFromDate, interestPostingUpToDate));
|
||||
break;
|
||||
case INVALID:
|
||||
actualDepositPeriod = this.depositPeriod;// default value
|
||||
break;
|
||||
}
|
||||
return actualDepositPeriod;
|
||||
}
|
||||
|
||||
public BigDecimal maturityAmount() {
|
||||
return this.maturityAmount;
|
||||
}
|
||||
|
||||
public void updateOnAccountClosureStatus(final DepositAccountOnClosureType onClosureType) {
|
||||
this.onAccountClosureType = onClosureType.getValue();
|
||||
}
|
||||
|
||||
public boolean isReinvestOnClosure() {
|
||||
return DepositAccountOnClosureType.fromInt(this.onAccountClosureType).isReinvest();
|
||||
}
|
||||
|
||||
public boolean isTransferToSavingsOnClosure() {
|
||||
return DepositAccountOnClosureType.fromInt(this.onAccountClosureType).isTransferToSavings();
|
||||
}
|
||||
|
||||
public DepositAccountTermAndPreClosure copy(BigDecimal depositAmount) {
|
||||
final SavingsAccount account = null;
|
||||
final BigDecimal maturityAmount = null;
|
||||
final BigDecimal actualDepositAmount = depositAmount;
|
||||
final LocalDate maturityDate = null;
|
||||
final Integer depositPeriod = this.depositPeriod;
|
||||
final SavingsPeriodFrequencyType depositPeriodFrequency = SavingsPeriodFrequencyType.fromInt(this.depositPeriodFrequency);
|
||||
final DepositPreClosureDetail preClosureDetail = this.preClosureDetail.copy();
|
||||
final DepositTermDetail depositTermDetail = this.depositTermDetail.copy();
|
||||
final LocalDate expectedFirstDepositOnDate = null;
|
||||
final Boolean transferInterestToLinkedAccount = false;
|
||||
|
||||
final DepositAccountOnClosureType accountOnClosureType = null;
|
||||
final Long transferToSavingsId = null;
|
||||
return DepositAccountTermAndPreClosure.createNew(preClosureDetail, depositTermDetail, account, actualDepositAmount, maturityAmount,
|
||||
maturityDate, depositPeriod, depositPeriodFrequency, expectedFirstDepositOnDate, accountOnClosureType,
|
||||
transferInterestToLinkedAccount, transferToSavingsId);
|
||||
}
|
||||
|
||||
public void updateExpectedFirstDepositDate(final LocalDate expectedFirstDepositOnDate) {
|
||||
this.expectedFirstDepositOnDate = expectedFirstDepositOnDate;
|
||||
}
|
||||
|
||||
public boolean isTransferInterestToLinkedAccount() {
|
||||
return this.transferInterestToLinkedAccount;
|
||||
}
|
||||
|
||||
public boolean isAfterExpectedFirstDepositDate(final LocalDate compareDate) {
|
||||
return this.expectedFirstDepositOnDate != null && DateUtils.isAfter(compareDate, getExpectedFirstDepositOnDate());
|
||||
}
|
||||
|
||||
public Integer getOnAccountClosureType() {
|
||||
return onAccountClosureType;
|
||||
}
|
||||
|
||||
public Long getTransferToSavingsAccountId() {
|
||||
return transferToSavingsAccountId;
|
||||
}
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* 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 static org.apache.fineract.portfolio.savings.DepositsApiConstants.preClosurePenalApplicableParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.preClosurePenalInterestOnTypeIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.preClosurePenalInterestParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.localeParamName;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.portfolio.savings.PreClosurePenalInterestOnType;
|
||||
import org.apache.fineract.portfolio.savings.service.SavingsEnumerations;
|
||||
|
||||
/**
|
||||
* DepositPreClosureDetail encapsulates all the details of a {@link FixedDepositProduct} that are also used and
|
||||
* persisted by a {@link FixedDepositAccount}.
|
||||
*/
|
||||
@Embeddable
|
||||
public class DepositPreClosureDetail {
|
||||
|
||||
@Column(name = "pre_closure_penal_applicable")
|
||||
private boolean preClosurePenalApplicable;
|
||||
|
||||
@Column(name = "pre_closure_penal_interest", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal preClosurePenalInterest;
|
||||
|
||||
@Column(name = "pre_closure_penal_interest_on_enum", nullable = true)
|
||||
private Integer preClosurePenalInterestOnType;
|
||||
|
||||
public static DepositPreClosureDetail createFrom(final boolean preClosurePenalApplicable, final BigDecimal preClosurePenalInterest,
|
||||
final PreClosurePenalInterestOnType preClosurePenalInterestType) {
|
||||
|
||||
return new DepositPreClosureDetail(preClosurePenalApplicable, preClosurePenalInterest, preClosurePenalInterestType);
|
||||
}
|
||||
|
||||
protected DepositPreClosureDetail() {
|
||||
//
|
||||
}
|
||||
|
||||
private DepositPreClosureDetail(final boolean preClosurePenalApplicable, final BigDecimal preClosurePenalInterest,
|
||||
final PreClosurePenalInterestOnType preClosurePenalInterestType) {
|
||||
this.preClosurePenalApplicable = preClosurePenalApplicable;
|
||||
this.preClosurePenalInterest = preClosurePenalInterest;
|
||||
this.preClosurePenalInterestOnType = (preClosurePenalInterestType == null) ? null : preClosurePenalInterestType.getValue();
|
||||
}
|
||||
|
||||
protected Map<String, Object> update(final JsonCommand command, final DataValidatorBuilder baseDataValidator) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(10);
|
||||
|
||||
final String localeAsInput = command.locale();
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(preClosurePenalApplicableParamName, this.preClosurePenalApplicable)) {
|
||||
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(preClosurePenalApplicableParamName);
|
||||
actualChanges.put(preClosurePenalApplicableParamName, newValue);
|
||||
this.preClosurePenalApplicable = newValue;
|
||||
}
|
||||
|
||||
if (this.preClosurePenalApplicable) {
|
||||
if (command.isChangeInBigDecimalParameterNamed(preClosurePenalInterestParamName, this.preClosurePenalInterest)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(preClosurePenalInterestParamName);
|
||||
actualChanges.put(preClosurePenalInterestParamName, newValue);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.preClosurePenalInterest = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(preClosurePenalInterestOnTypeIdParamName, this.preClosurePenalInterestOnType)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(preClosurePenalInterestOnTypeIdParamName);
|
||||
actualChanges.put(preClosurePenalInterestOnTypeIdParamName, SavingsEnumerations.preClosurePenaltyInterestOnType(newValue));
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.preClosurePenalInterestOnType = newValue;
|
||||
}
|
||||
|
||||
if (this.preClosurePenalInterest == null) {
|
||||
baseDataValidator.parameter(preClosurePenalInterestParamName).value(this.preClosurePenalInterest)
|
||||
.cantBeBlankWhenParameterProvidedIs(preClosurePenalApplicableParamName, this.preClosurePenalApplicable);
|
||||
}
|
||||
|
||||
if (this.preClosurePenalInterestOnType == null) {
|
||||
baseDataValidator.parameter(preClosurePenalInterestOnTypeIdParamName).value(this.preClosurePenalInterestOnType)
|
||||
.cantBeBlankWhenParameterProvidedIs(preClosurePenalApplicableParamName, this.preClosurePenalApplicable);
|
||||
}
|
||||
} else { // reset if pre-closure penal interest is not applicable
|
||||
this.preClosurePenalInterest = null;
|
||||
this.preClosurePenalInterestOnType = null;
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public boolean preClosurePenalApplicable() {
|
||||
return this.preClosurePenalApplicable;
|
||||
}
|
||||
|
||||
public BigDecimal preClosurePenalInterest() {
|
||||
return this.preClosurePenalInterest;
|
||||
}
|
||||
|
||||
public Integer preClosurePenalInterestOnTypeId() {
|
||||
return this.preClosurePenalInterestOnType;
|
||||
}
|
||||
|
||||
public PreClosurePenalInterestOnType preClosurePenalInterestOnType() {
|
||||
return PreClosurePenalInterestOnType.fromInt(preClosurePenalInterestOnType);
|
||||
}
|
||||
|
||||
public DepositPreClosureDetail copy() {
|
||||
final boolean preClosurePenalApplicable = this.preClosurePenalApplicable;
|
||||
final BigDecimal preClosurePenalInterest = this.preClosurePenalInterest;
|
||||
final PreClosurePenalInterestOnType preClosurePenalInterestType = PreClosurePenalInterestOnType
|
||||
.fromInt(this.preClosurePenalInterestOnType);
|
||||
|
||||
return DepositPreClosureDetail.createFrom(preClosurePenalApplicable, preClosurePenalInterest, preClosurePenalInterestType);
|
||||
}
|
||||
}
|
||||
+105
@@ -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.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
|
||||
/**
|
||||
* RecurringDepositProductAmountDetails encapsulates all recurring Deposit Amount of a {@link RecurringDepositProduct}.
|
||||
*/
|
||||
@Embeddable
|
||||
public class DepositProductAmountDetails {
|
||||
|
||||
@Column(name = "min_deposit_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal minDepositAmount;
|
||||
|
||||
@Column(name = "max_deposit_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal maxDepositAmount;
|
||||
|
||||
@Column(name = "deposit_amount", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal depositAmount;
|
||||
|
||||
public static DepositProductAmountDetails createFrom(final BigDecimal minDepositAmount, final BigDecimal depositAmount,
|
||||
final BigDecimal maxDepositAmount) {
|
||||
|
||||
return new DepositProductAmountDetails(minDepositAmount, depositAmount, maxDepositAmount);
|
||||
}
|
||||
|
||||
protected DepositProductAmountDetails() {
|
||||
//
|
||||
}
|
||||
|
||||
public DepositProductAmountDetails(final BigDecimal minDepositAmount, final BigDecimal depositAmount,
|
||||
final BigDecimal maxDepositAmount) {
|
||||
this.minDepositAmount = minDepositAmount;
|
||||
this.depositAmount = depositAmount;
|
||||
this.maxDepositAmount = maxDepositAmount;
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command) {
|
||||
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(20);
|
||||
|
||||
final String localeAsInput = command.locale();
|
||||
|
||||
final String minDepositAmountParamName = "minDepositAmount";
|
||||
if (command.isChangeInBigDecimalParameterNamedWithNullCheck(minDepositAmountParamName, this.minDepositAmount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minDepositAmountParamName);
|
||||
actualChanges.put(minDepositAmountParamName, newValue);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.minDepositAmount = newValue;
|
||||
}
|
||||
|
||||
final String maxDepositAmountParamName = "maxDepositAmount";
|
||||
if (command.isChangeInBigDecimalParameterNamedWithNullCheck(maxDepositAmountParamName, this.maxDepositAmount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(maxDepositAmountParamName);
|
||||
actualChanges.put(maxDepositAmountParamName, newValue);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.maxDepositAmount = newValue;
|
||||
}
|
||||
|
||||
final String depositAmountParamName = "depositAmount";
|
||||
if (command.isChangeInBigDecimalParameterNamedWithNullCheck(depositAmountParamName, this.depositAmount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(depositAmountParamName);
|
||||
actualChanges.put(depositAmountParamName, newValue);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.depositAmount = newValue;
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public BigDecimal getMinDepositAmount() {
|
||||
return this.minDepositAmount;
|
||||
}
|
||||
|
||||
public BigDecimal getMaxDepositAmount() {
|
||||
return this.maxDepositAmount;
|
||||
}
|
||||
|
||||
public BigDecimal getDepositAmount() {
|
||||
return this.depositAmount;
|
||||
}
|
||||
|
||||
}
|
||||
+527
@@ -0,0 +1,527 @@
|
||||
/**
|
||||
* 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 static org.apache.fineract.portfolio.savings.DepositsApiConstants.FIXED_DEPOSIT_PRODUCT_RESOURCE_NAME;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.RECURRING_DEPOSIT_PRODUCT_RESOURCE_NAME;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.adjustAdvanceTowardsFuturePaymentsParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.allowWithdrawalParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.chartsParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.depositAmountParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.depositMaxAmountParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.depositMinAmountParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.inMultiplesOfDepositTermParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.inMultiplesOfDepositTermTypeIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.isMandatoryDepositParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.maxDepositTermParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.maxDepositTermTypeIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.minDepositTermParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.minDepositTermTypeIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.preClosurePenalApplicableParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.preClosurePenalInterestOnTypeIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.preClosurePenalInterestParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargesParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.currencyCodeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.descriptionParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.digitsAfterDecimalParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.idParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.inMultiplesOfParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCalculationDaysInYearTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCalculationTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCompoundingPeriodTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestPostingPeriodTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.minBalanceForInterestCalculationParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nameParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.shortNameParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.taxGroupIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHoldTaxParamName;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.exception.InvalidCurrencyException;
|
||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.charge.exception.ChargeCannotBeAppliedToException;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestRateChart;
|
||||
import org.apache.fineract.portfolio.interestratechart.service.InterestRateChartAssembler;
|
||||
import org.apache.fineract.portfolio.savings.PreClosurePenalInterestOnType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.apache.fineract.portfolio.tax.domain.TaxGroup;
|
||||
import org.apache.fineract.portfolio.tax.domain.TaxGroupRepositoryWrapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class DepositProductAssembler {
|
||||
|
||||
private final ChargeRepositoryWrapper chargeRepository;
|
||||
private final InterestRateChartAssembler chartAssembler;
|
||||
private final TaxGroupRepositoryWrapper taxGroupRepository;
|
||||
|
||||
@Autowired
|
||||
public DepositProductAssembler(final ChargeRepositoryWrapper chargeRepository, final InterestRateChartAssembler chartAssembler,
|
||||
final TaxGroupRepositoryWrapper taxGroupRepository) {
|
||||
this.chargeRepository = chargeRepository;
|
||||
this.chartAssembler = chartAssembler;
|
||||
this.taxGroupRepository = taxGroupRepository;
|
||||
}
|
||||
|
||||
public FixedDepositProduct assembleFixedDepositProduct(final JsonCommand command) {
|
||||
|
||||
final String name = command.stringValueOfParameterNamed(nameParamName);
|
||||
final String shortName = command.stringValueOfParameterNamed(shortNameParamName);
|
||||
final String description = command.stringValueOfParameterNamed(descriptionParamName);
|
||||
|
||||
final String currencyCode = command.stringValueOfParameterNamed(currencyCodeParamName);
|
||||
final Integer digitsAfterDecimal = command.integerValueOfParameterNamed(digitsAfterDecimalParamName);
|
||||
final Integer inMultiplesOf = command.integerValueOfParameterNamed(inMultiplesOfParamName);
|
||||
final MonetaryCurrency currency = new MonetaryCurrency(currencyCode, digitsAfterDecimal, inMultiplesOf);
|
||||
|
||||
BigDecimal interestRate = command.bigDecimalValueOfParameterNamed(nominalAnnualInterestRateParamName);
|
||||
|
||||
SavingsCompoundingInterestPeriodType interestCompoundingPeriodType = null;
|
||||
final Integer interestPeriodTypeValue = command.integerValueOfParameterNamed(interestCompoundingPeriodTypeParamName);
|
||||
if (interestPeriodTypeValue != null) {
|
||||
interestCompoundingPeriodType = SavingsCompoundingInterestPeriodType.fromInt(interestPeriodTypeValue);
|
||||
}
|
||||
|
||||
SavingsPostingInterestPeriodType interestPostingPeriodType = null;
|
||||
final Integer interestPostingPeriodTypeValue = command.integerValueOfParameterNamed(interestPostingPeriodTypeParamName);
|
||||
if (interestPostingPeriodTypeValue != null) {
|
||||
interestPostingPeriodType = SavingsPostingInterestPeriodType.fromInt(interestPostingPeriodTypeValue);
|
||||
}
|
||||
|
||||
SavingsInterestCalculationType interestCalculationType = null;
|
||||
final Integer interestCalculationTypeValue = command.integerValueOfParameterNamed(interestCalculationTypeParamName);
|
||||
if (interestCalculationTypeValue != null) {
|
||||
interestCalculationType = SavingsInterestCalculationType.fromInt(interestCalculationTypeValue);
|
||||
}
|
||||
|
||||
SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType = null;
|
||||
final Integer interestCalculationDaysInYearTypeValue = command
|
||||
.integerValueOfParameterNamed(interestCalculationDaysInYearTypeParamName);
|
||||
if (interestCalculationDaysInYearTypeValue != null) {
|
||||
interestCalculationDaysInYearType = SavingsInterestCalculationDaysInYearType.fromInt(interestCalculationDaysInYearTypeValue);
|
||||
}
|
||||
|
||||
final Integer lockinPeriodFrequency = command.integerValueOfParameterNamedDefaultToNullIfZero(lockinPeriodFrequencyParamName);
|
||||
SavingsPeriodFrequencyType lockinPeriodFrequencyType = null;
|
||||
final Integer lockinPeriodFrequencyTypeValue = command.integerValueOfParameterNamed(lockinPeriodFrequencyTypeParamName);
|
||||
if (lockinPeriodFrequencyTypeValue != null) {
|
||||
lockinPeriodFrequencyType = SavingsPeriodFrequencyType.fromInt(lockinPeriodFrequencyTypeValue);
|
||||
}
|
||||
|
||||
final BigDecimal minBalanceForInterestCalculation = command
|
||||
.bigDecimalValueOfParameterNamedDefaultToNullIfZero(minBalanceForInterestCalculationParamName);
|
||||
|
||||
final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(command.integerValueOfParameterNamed("accountingRule"));
|
||||
|
||||
final DepositPreClosureDetail preClosureDetail = this.assemblePreClosureDetail(command);
|
||||
final DepositTermDetail depositTermDetail = this.assembleDepositTermDetail(command);
|
||||
final DepositProductAmountDetails depositProductAmountDetails = this.assembleDepositAmountDetails(command);
|
||||
final DepositProductTermAndPreClosure productTermAndPreClosure = DepositProductTermAndPreClosure.createNew(preClosureDetail,
|
||||
depositTermDetail, depositProductAmountDetails, null);
|
||||
|
||||
// Savings product charges
|
||||
final Set<Charge> charges = assembleListOfSavingsProductCharges(command, currencyCode);
|
||||
// Interest rate charts
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(FIXED_DEPOSIT_PRODUCT_RESOURCE_NAME);
|
||||
final Set<InterestRateChart> charts = assembleListOfCharts(command, currency.getCode(), baseDataValidator);
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
if (interestRate == null) {
|
||||
interestRate = BigDecimal.ZERO;
|
||||
}
|
||||
boolean withHoldTax = command.booleanPrimitiveValueOfParameterNamed(withHoldTaxParamName);
|
||||
|
||||
final Long taxGroupId = command.longValueOfParameterNamed(taxGroupIdParamName);
|
||||
TaxGroup taxGroup = null;
|
||||
if (taxGroupId != null) {
|
||||
taxGroup = this.taxGroupRepository.findOneWithNotFoundDetection(taxGroupId);
|
||||
}
|
||||
|
||||
FixedDepositProduct fixedDepositProduct = FixedDepositProduct.createNew(name, shortName, description, currency, interestRate,
|
||||
interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, accountingRuleType, charges, productTermAndPreClosure, charts,
|
||||
minBalanceForInterestCalculation, withHoldTax, taxGroup);
|
||||
|
||||
// update product reference
|
||||
productTermAndPreClosure.updateProductReference(fixedDepositProduct);
|
||||
|
||||
fixedDepositProduct.validateDomainRules();
|
||||
|
||||
return fixedDepositProduct;
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
public RecurringDepositProduct assembleRecurringDepositProduct(final JsonCommand command) {
|
||||
|
||||
final String name = command.stringValueOfParameterNamed(nameParamName);
|
||||
final String shortName = command.stringValueOfParameterNamed(shortNameParamName);
|
||||
final String description = command.stringValueOfParameterNamed(descriptionParamName);
|
||||
|
||||
final String currencyCode = command.stringValueOfParameterNamed(currencyCodeParamName);
|
||||
final Integer digitsAfterDecimal = command.integerValueOfParameterNamed(digitsAfterDecimalParamName);
|
||||
final Integer inMultiplesOf = command.integerValueOfParameterNamed(inMultiplesOfParamName);
|
||||
final MonetaryCurrency currency = new MonetaryCurrency(currencyCode, digitsAfterDecimal, inMultiplesOf);
|
||||
|
||||
BigDecimal interestRate = command.bigDecimalValueOfParameterNamed(nominalAnnualInterestRateParamName);
|
||||
|
||||
SavingsCompoundingInterestPeriodType interestCompoundingPeriodType = null;
|
||||
final Integer interestPeriodTypeValue = command.integerValueOfParameterNamed(interestCompoundingPeriodTypeParamName);
|
||||
if (interestPeriodTypeValue != null) {
|
||||
interestCompoundingPeriodType = SavingsCompoundingInterestPeriodType.fromInt(interestPeriodTypeValue);
|
||||
}
|
||||
|
||||
SavingsPostingInterestPeriodType interestPostingPeriodType = null;
|
||||
final Integer interestPostingPeriodTypeValue = command.integerValueOfParameterNamed(interestPostingPeriodTypeParamName);
|
||||
if (interestPostingPeriodTypeValue != null) {
|
||||
interestPostingPeriodType = SavingsPostingInterestPeriodType.fromInt(interestPostingPeriodTypeValue);
|
||||
}
|
||||
|
||||
SavingsInterestCalculationType interestCalculationType = null;
|
||||
final Integer interestCalculationTypeValue = command.integerValueOfParameterNamed(interestCalculationTypeParamName);
|
||||
if (interestCalculationTypeValue != null) {
|
||||
interestCalculationType = SavingsInterestCalculationType.fromInt(interestCalculationTypeValue);
|
||||
}
|
||||
|
||||
SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType = null;
|
||||
final Integer interestCalculationDaysInYearTypeValue = command
|
||||
.integerValueOfParameterNamed(interestCalculationDaysInYearTypeParamName);
|
||||
if (interestCalculationDaysInYearTypeValue != null) {
|
||||
interestCalculationDaysInYearType = SavingsInterestCalculationDaysInYearType.fromInt(interestCalculationDaysInYearTypeValue);
|
||||
}
|
||||
|
||||
final Integer lockinPeriodFrequency = command.integerValueOfParameterNamedDefaultToNullIfZero(lockinPeriodFrequencyParamName);
|
||||
SavingsPeriodFrequencyType lockinPeriodFrequencyType = null;
|
||||
final Integer lockinPeriodFrequencyTypeValue = command.integerValueOfParameterNamed(lockinPeriodFrequencyTypeParamName);
|
||||
if (lockinPeriodFrequencyTypeValue != null) {
|
||||
lockinPeriodFrequencyType = SavingsPeriodFrequencyType.fromInt(lockinPeriodFrequencyTypeValue);
|
||||
}
|
||||
|
||||
final BigDecimal minBalanceForInterestCalculation = command
|
||||
.bigDecimalValueOfParameterNamedDefaultToNullIfZero(minBalanceForInterestCalculationParamName);
|
||||
|
||||
final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(command.integerValueOfParameterNamed("accountingRule"));
|
||||
|
||||
final DepositPreClosureDetail preClosureDetail = this.assemblePreClosureDetail(command);
|
||||
final DepositTermDetail depositTermDetail = this.assembleDepositTermDetail(command);
|
||||
final DepositProductAmountDetails depositProductAmountDetails = this.assembleDepositAmountDetails(command);
|
||||
final DepositProductTermAndPreClosure productTermAndPreClosure = DepositProductTermAndPreClosure.createNew(preClosureDetail,
|
||||
depositTermDetail, depositProductAmountDetails, null);
|
||||
final DepositRecurringDetail recurringDetail = this.assembleRecurringDetail(command);
|
||||
final DepositProductRecurringDetail productRecurringDetail = DepositProductRecurringDetail.createNew(recurringDetail, null);
|
||||
|
||||
// Savings product charges
|
||||
final Set<Charge> charges = assembleListOfSavingsProductCharges(command, currencyCode);
|
||||
// Interest rate charts
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(RECURRING_DEPOSIT_PRODUCT_RESOURCE_NAME);
|
||||
final Set<InterestRateChart> charts = assembleListOfCharts(command, currency.getCode(), baseDataValidator);
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
|
||||
if (interestRate == null) {
|
||||
interestRate = BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
final boolean withHoldTax = command.booleanPrimitiveValueOfParameterNamed(withHoldTaxParamName);
|
||||
final TaxGroup taxGroup = assembleTaxGroup(command);
|
||||
|
||||
RecurringDepositProduct recurringDepositProduct = RecurringDepositProduct.createNew(name, shortName, description, currency,
|
||||
interestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType,
|
||||
interestCalculationDaysInYearType, lockinPeriodFrequency, lockinPeriodFrequencyType, accountingRuleType, charges,
|
||||
productTermAndPreClosure, productRecurringDetail, charts, minBalanceForInterestCalculation, taxGroup, withHoldTax);
|
||||
|
||||
// update product reference
|
||||
productTermAndPreClosure.updateProductReference(recurringDepositProduct);
|
||||
productRecurringDetail.updateProductReference(recurringDepositProduct);
|
||||
|
||||
recurringDepositProduct.validateDomainRules();
|
||||
|
||||
return recurringDepositProduct;
|
||||
}
|
||||
|
||||
public DepositPreClosureDetail assemblePreClosureDetail(final JsonCommand command) {
|
||||
|
||||
boolean preClosurePenalApplicable = false;
|
||||
BigDecimal preClosurePenalInterest = null;
|
||||
PreClosurePenalInterestOnType preClosurePenalInterestType = null;
|
||||
|
||||
if (command.parameterExists(preClosurePenalApplicableParamName)) {
|
||||
preClosurePenalApplicable = command.booleanObjectValueOfParameterNamed(preClosurePenalApplicableParamName);
|
||||
if (preClosurePenalApplicable) {
|
||||
preClosurePenalInterest = command.bigDecimalValueOfParameterNamed(preClosurePenalInterestParamName);
|
||||
final Integer preClosurePenalInterestOnTypeId = command
|
||||
.integerValueOfParameterNamed(preClosurePenalInterestOnTypeIdParamName);
|
||||
preClosurePenalInterestType = preClosurePenalInterestOnTypeId == null ? null
|
||||
: PreClosurePenalInterestOnType.fromInt(preClosurePenalInterestOnTypeId);
|
||||
}
|
||||
}
|
||||
|
||||
DepositPreClosureDetail preClosureDetail = DepositPreClosureDetail.createFrom(preClosurePenalApplicable, preClosurePenalInterest,
|
||||
preClosurePenalInterestType);
|
||||
|
||||
return preClosureDetail;
|
||||
}
|
||||
|
||||
public DepositPreClosureDetail assemblePreClosureDetail(final JsonCommand command, DepositPreClosureDetail produPreClosureDetail) {
|
||||
boolean preClosurePenalApplicable = false;
|
||||
BigDecimal preClosurePenalInterest = null;
|
||||
PreClosurePenalInterestOnType preClosurePenalInterestType = null;
|
||||
Integer preClosurePenalInterestOnTypeId = null;
|
||||
if (command.parameterExists(preClosurePenalApplicableParamName)) {
|
||||
preClosurePenalApplicable = command.booleanObjectValueOfParameterNamed(preClosurePenalApplicableParamName);
|
||||
if (preClosurePenalApplicable) {
|
||||
if (command.parameterExists(preClosurePenalInterestParamName)) {
|
||||
preClosurePenalInterest = command.bigDecimalValueOfParameterNamed(preClosurePenalInterestParamName);
|
||||
} else {
|
||||
preClosurePenalInterest = produPreClosureDetail.preClosurePenalInterest();
|
||||
}
|
||||
|
||||
if (command.parameterExists(preClosurePenalInterestParamName)) {
|
||||
preClosurePenalInterestOnTypeId = command.integerValueOfParameterNamed(preClosurePenalInterestOnTypeIdParamName);
|
||||
} else {
|
||||
preClosurePenalInterestOnTypeId = produPreClosureDetail.preClosurePenalInterestOnTypeId();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
preClosurePenalApplicable = produPreClosureDetail.preClosurePenalApplicable();
|
||||
preClosurePenalInterest = produPreClosureDetail.preClosurePenalInterest();
|
||||
preClosurePenalInterestOnTypeId = produPreClosureDetail.preClosurePenalInterestOnTypeId();
|
||||
}
|
||||
|
||||
preClosurePenalInterestType = preClosurePenalInterestOnTypeId == null ? null
|
||||
: PreClosurePenalInterestOnType.fromInt(preClosurePenalInterestOnTypeId);
|
||||
|
||||
DepositPreClosureDetail preClosureDetail1 = DepositPreClosureDetail.createFrom(preClosurePenalApplicable, preClosurePenalInterest,
|
||||
preClosurePenalInterestType);
|
||||
|
||||
return preClosureDetail1;
|
||||
}
|
||||
|
||||
public DepositTermDetail assembleDepositTermDetail(final JsonCommand command) {
|
||||
|
||||
final Integer minDepositTerm = command.integerValueOfParameterNamed(minDepositTermParamName);
|
||||
final Integer maxDepositTerm = command.integerValueOfParameterNamed(maxDepositTermParamName);
|
||||
final Integer minDepositTermTypeId = command.integerValueOfParameterNamed(minDepositTermTypeIdParamName);
|
||||
final SavingsPeriodFrequencyType minDepositTermType = (minDepositTermTypeId == null) ? null
|
||||
: SavingsPeriodFrequencyType.fromInt(minDepositTermTypeId);
|
||||
final Integer maxDepositTermTypeId = command.integerValueOfParameterNamed(maxDepositTermTypeIdParamName);
|
||||
final SavingsPeriodFrequencyType maxDepositTermType = (maxDepositTermTypeId == null) ? null
|
||||
: SavingsPeriodFrequencyType.fromInt(maxDepositTermTypeId);
|
||||
final Integer inMultiplesOfDepositTerm = command.integerValueOfParameterNamed(inMultiplesOfDepositTermParamName);
|
||||
final Integer inMultiplesOfDepositTermTypeId = command.integerValueOfParameterNamed(inMultiplesOfDepositTermTypeIdParamName);
|
||||
final SavingsPeriodFrequencyType inMultiplesOfDepositTermType = (inMultiplesOfDepositTermTypeId == null) ? null
|
||||
: SavingsPeriodFrequencyType.fromInt(inMultiplesOfDepositTermTypeId);
|
||||
|
||||
final DepositTermDetail depositTermDetail = DepositTermDetail.createFrom(minDepositTerm, maxDepositTerm, minDepositTermType,
|
||||
maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType);
|
||||
|
||||
return depositTermDetail;
|
||||
}
|
||||
|
||||
public DepositTermDetail assembleDepositTermDetail(final JsonCommand command, final DepositTermDetail prodDepositTermDetail) {
|
||||
|
||||
Integer minDepositTerm = null;
|
||||
Integer maxDepositTerm = null;
|
||||
Integer minDepositTermTypeId = null;
|
||||
Integer maxDepositTermTypeId = null;
|
||||
Integer inMultiplesOfDepositTerm = null;
|
||||
Integer inMultiplesOfDepositTermTypeId = null;
|
||||
|
||||
if (command.parameterExists(minDepositTermParamName)) {
|
||||
minDepositTerm = command.integerValueOfParameterNamed(minDepositTermParamName);
|
||||
} else if (prodDepositTermDetail != null) {
|
||||
minDepositTerm = prodDepositTermDetail.minDepositTerm();
|
||||
}
|
||||
|
||||
if (command.parameterExists(maxDepositTermParamName)) {
|
||||
maxDepositTerm = command.integerValueOfParameterNamed(maxDepositTermParamName);
|
||||
} else if (prodDepositTermDetail != null) {
|
||||
maxDepositTerm = prodDepositTermDetail.maxDepositTerm();
|
||||
}
|
||||
|
||||
if (command.parameterExists(minDepositTermTypeIdParamName)) {
|
||||
minDepositTermTypeId = command.integerValueOfParameterNamed(minDepositTermTypeIdParamName);
|
||||
} else if (prodDepositTermDetail != null) {
|
||||
minDepositTermTypeId = prodDepositTermDetail.minDepositTermType();
|
||||
}
|
||||
|
||||
if (command.parameterExists(maxDepositTermTypeIdParamName)) {
|
||||
maxDepositTermTypeId = command.integerValueOfParameterNamed(maxDepositTermTypeIdParamName);
|
||||
} else if (prodDepositTermDetail != null) {
|
||||
maxDepositTermTypeId = prodDepositTermDetail.maxDepositTermType();
|
||||
}
|
||||
|
||||
final SavingsPeriodFrequencyType minDepositTermType = (minDepositTermTypeId == null) ? null
|
||||
: SavingsPeriodFrequencyType.fromInt(minDepositTermTypeId);
|
||||
|
||||
final SavingsPeriodFrequencyType maxDepositTermType = (maxDepositTermTypeId == null) ? null
|
||||
: SavingsPeriodFrequencyType.fromInt(maxDepositTermTypeId);
|
||||
|
||||
if (command.parameterExists(inMultiplesOfDepositTermParamName)) {
|
||||
inMultiplesOfDepositTerm = command.integerValueOfParameterNamed(inMultiplesOfDepositTermParamName);
|
||||
} else if (prodDepositTermDetail != null) {
|
||||
inMultiplesOfDepositTerm = prodDepositTermDetail.inMultiplesOfDepositTerm();
|
||||
}
|
||||
|
||||
if (command.parameterExists(preClosurePenalApplicableParamName)) {
|
||||
inMultiplesOfDepositTermTypeId = command.integerValueOfParameterNamed(inMultiplesOfDepositTermTypeIdParamName);
|
||||
} else if (prodDepositTermDetail != null) {
|
||||
inMultiplesOfDepositTermTypeId = prodDepositTermDetail.inMultiplesOfDepositTermType();
|
||||
}
|
||||
|
||||
final SavingsPeriodFrequencyType inMultiplesOfDepositTermType = (inMultiplesOfDepositTermTypeId == null) ? null
|
||||
: SavingsPeriodFrequencyType.fromInt(inMultiplesOfDepositTermTypeId);
|
||||
|
||||
final DepositTermDetail depositTermDetail = DepositTermDetail.createFrom(minDepositTerm, maxDepositTerm, minDepositTermType,
|
||||
maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType);
|
||||
|
||||
return depositTermDetail;
|
||||
}
|
||||
|
||||
public DepositRecurringDetail assembleRecurringDetail(final JsonCommand command) {
|
||||
|
||||
Boolean isMandatoryDeposit = command.booleanObjectValueOfParameterNamed(isMandatoryDepositParamName);
|
||||
Boolean allowWithdrawal = command.booleanObjectValueOfParameterNamed(allowWithdrawalParamName);
|
||||
Boolean adjustAdvanceTowardsFuturePayments = command
|
||||
.booleanObjectValueOfParameterNamed(adjustAdvanceTowardsFuturePaymentsParamName);
|
||||
|
||||
if (isMandatoryDeposit == null) {
|
||||
isMandatoryDeposit = false;
|
||||
}
|
||||
if (allowWithdrawal == null) {
|
||||
allowWithdrawal = false;
|
||||
}
|
||||
if (adjustAdvanceTowardsFuturePayments == null) {
|
||||
adjustAdvanceTowardsFuturePayments = false;
|
||||
}
|
||||
|
||||
final DepositRecurringDetail depositRecurringDetail = DepositRecurringDetail.createFrom(isMandatoryDeposit, allowWithdrawal,
|
||||
adjustAdvanceTowardsFuturePayments);
|
||||
|
||||
return depositRecurringDetail;
|
||||
}
|
||||
|
||||
public Set<Charge> assembleListOfSavingsProductCharges(final JsonCommand command, final String savingsProductCurrencyCode) {
|
||||
|
||||
final Set<Charge> charges = new HashSet<>();
|
||||
|
||||
if (command.parameterExists(chargesParamName)) {
|
||||
final JsonArray chargesArray = command.arrayOfParameterNamed(chargesParamName);
|
||||
if (chargesArray != null) {
|
||||
for (int i = 0; i < chargesArray.size(); i++) {
|
||||
|
||||
final JsonObject jsonObject = chargesArray.get(i).getAsJsonObject();
|
||||
if (jsonObject.has(idParamName)) {
|
||||
final Long id = jsonObject.get(idParamName).getAsLong();
|
||||
|
||||
final Charge charge = this.chargeRepository.findOneWithNotFoundDetection(id);
|
||||
|
||||
if (!charge.isSavingsCharge()) {
|
||||
final String errorMessage = "Charge with identifier " + charge.getId()
|
||||
+ " cannot be applied to Savings product.";
|
||||
throw new ChargeCannotBeAppliedToException("savings.product", errorMessage, charge.getId());
|
||||
}
|
||||
|
||||
if (!savingsProductCurrencyCode.equals(charge.getCurrencyCode())) {
|
||||
final String errorMessage = "Charge and Savings Product must have the same currency.";
|
||||
throw new InvalidCurrencyException("charge", "attach.to.savings.product", errorMessage);
|
||||
}
|
||||
charges.add(charge);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return charges;
|
||||
}
|
||||
|
||||
private Set<InterestRateChart> assembleListOfCharts(JsonCommand command, String currencyCode, DataValidatorBuilder baseDataValidator) {
|
||||
final Set<InterestRateChart> charts = new HashSet<>();
|
||||
if (command.parameterExists(chartsParamName)) {
|
||||
final JsonArray chartsArray = command.arrayOfParameterNamed(chartsParamName);
|
||||
if (chartsArray != null) {
|
||||
for (int i = 0; i < chartsArray.size(); i++) {
|
||||
final JsonObject interstRateChartElement = chartsArray.get(i).getAsJsonObject();
|
||||
InterestRateChart chart = this.chartAssembler.assembleFrom(interstRateChartElement, currencyCode, baseDataValidator);
|
||||
charts.add(chart);
|
||||
}
|
||||
}
|
||||
}
|
||||
return charts;
|
||||
}
|
||||
|
||||
public DepositProductAmountDetails assembleDepositAmountDetails(final JsonCommand command) {
|
||||
|
||||
BigDecimal minDepositAmount = null;
|
||||
if (command.parameterExists(depositMinAmountParamName)) {
|
||||
minDepositAmount = command.bigDecimalValueOfParameterNamed(depositMinAmountParamName);
|
||||
}
|
||||
|
||||
BigDecimal maxDepositAmount = null;
|
||||
if (command.parameterExists(depositMaxAmountParamName)) {
|
||||
maxDepositAmount = command.bigDecimalValueOfParameterNamed(depositMaxAmountParamName);
|
||||
}
|
||||
|
||||
BigDecimal depositAmount = null;
|
||||
if (command.parameterExists(depositAmountParamName)) {
|
||||
depositAmount = command.bigDecimalValueOfParameterNamed(depositAmountParamName);
|
||||
}
|
||||
|
||||
final DepositProductAmountDetails depositRecurringDetail = new DepositProductAmountDetails(minDepositAmount, depositAmount,
|
||||
maxDepositAmount);
|
||||
|
||||
return depositRecurringDetail;
|
||||
}
|
||||
|
||||
public TaxGroup assembleTaxGroup(final JsonCommand command) {
|
||||
final Long taxGroupId = command.longValueOfParameterNamed(taxGroupIdParamName);
|
||||
TaxGroup taxGroup = null;
|
||||
if (taxGroupId != null) {
|
||||
taxGroup = this.taxGroupRepository.findOneWithNotFoundDetection(taxGroupId);
|
||||
}
|
||||
return taxGroup;
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* 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 jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_deposit_product_recurring_detail")
|
||||
public class DepositProductRecurringDetail extends AbstractPersistableCustom {
|
||||
|
||||
@Embedded
|
||||
private DepositRecurringDetail recurringDetail;
|
||||
|
||||
@OneToOne
|
||||
@JoinColumn(name = "savings_product_id", nullable = false)
|
||||
private RecurringDepositProduct product;
|
||||
|
||||
protected DepositProductRecurringDetail() {
|
||||
|
||||
}
|
||||
|
||||
public static DepositProductRecurringDetail createNew(DepositRecurringDetail recurringDetail, SavingsProduct product) {
|
||||
|
||||
return new DepositProductRecurringDetail(recurringDetail, product);
|
||||
}
|
||||
|
||||
private DepositProductRecurringDetail(DepositRecurringDetail recurringDetail, SavingsProduct product) {
|
||||
this.recurringDetail = recurringDetail;
|
||||
this.product = (RecurringDepositProduct) product;
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(10);
|
||||
if (this.recurringDetail != null) {
|
||||
actualChanges.putAll(this.recurringDetail.update(command));
|
||||
}
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public DepositRecurringDetail recurringDetail() {
|
||||
return this.recurringDetail;
|
||||
}
|
||||
|
||||
public void updateProductReference(final SavingsProduct product) {
|
||||
this.product = (RecurringDepositProduct) product;
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_deposit_product_term_and_preclosure")
|
||||
public class DepositProductTermAndPreClosure extends AbstractPersistableCustom {
|
||||
|
||||
@Embedded
|
||||
private DepositPreClosureDetail preClosureDetail;
|
||||
|
||||
@Embedded
|
||||
protected DepositTermDetail depositTermDetail;
|
||||
|
||||
@OneToOne
|
||||
@JoinColumn(name = "savings_product_id", nullable = false)
|
||||
private FixedDepositProduct product;
|
||||
|
||||
@Embedded
|
||||
private DepositProductAmountDetails depositProductAmountDetails;
|
||||
|
||||
protected DepositProductTermAndPreClosure() {
|
||||
|
||||
}
|
||||
|
||||
public static DepositProductTermAndPreClosure createNew(DepositPreClosureDetail preClosureDetail, DepositTermDetail depositTermDetail,
|
||||
DepositProductAmountDetails depositProductMinMaxAmountDetails, SavingsProduct product) {
|
||||
|
||||
return new DepositProductTermAndPreClosure(preClosureDetail, depositTermDetail, depositProductMinMaxAmountDetails, product);
|
||||
}
|
||||
|
||||
private DepositProductTermAndPreClosure(DepositPreClosureDetail preClosureDetail, DepositTermDetail depositTermDetail,
|
||||
DepositProductAmountDetails depositProductMinMaxAmountDetails, SavingsProduct product) {
|
||||
this.preClosureDetail = preClosureDetail;
|
||||
this.depositTermDetail = depositTermDetail;
|
||||
this.depositProductAmountDetails = depositProductMinMaxAmountDetails;
|
||||
this.product = (FixedDepositProduct) product;
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command, final DataValidatorBuilder baseDataValidator) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(10);
|
||||
if (this.preClosureDetail != null) {
|
||||
actualChanges.putAll(this.preClosureDetail.update(command, baseDataValidator));
|
||||
}
|
||||
|
||||
if (this.depositTermDetail != null) {
|
||||
actualChanges.putAll(this.depositTermDetail.update(command, baseDataValidator));
|
||||
}
|
||||
|
||||
if (this.depositProductAmountDetails != null) {
|
||||
actualChanges.putAll(this.depositProductAmountDetails.update(command));
|
||||
}
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public DepositPreClosureDetail depositPreClosureDetail() {
|
||||
return this.preClosureDetail;
|
||||
}
|
||||
|
||||
public DepositTermDetail depositTermDetail() {
|
||||
return this.depositTermDetail;
|
||||
}
|
||||
|
||||
public DepositProductAmountDetails depositProductAmountDetails() {
|
||||
return this.depositProductAmountDetails;
|
||||
}
|
||||
|
||||
public void updateProductReference(final SavingsProduct product) {
|
||||
this.product = (FixedDepositProduct) product;
|
||||
}
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* 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 static org.apache.fineract.portfolio.savings.DepositsApiConstants.adjustAdvanceTowardsFuturePaymentsParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.allowWithdrawalParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.isMandatoryDepositParamName;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
|
||||
/**
|
||||
* DepositRecurringDetail encapsulates all the details of a {@link RecurringDepositProduct} that are also used and
|
||||
* persisted by a {@link RecurringDepositAccount}.
|
||||
*/
|
||||
@Embeddable
|
||||
public class DepositRecurringDetail {
|
||||
|
||||
@Column(name = "is_mandatory", nullable = true)
|
||||
private boolean isMandatoryDeposit;
|
||||
|
||||
@Column(name = "allow_withdrawal", nullable = true)
|
||||
private boolean allowWithdrawal;
|
||||
|
||||
@Column(name = "adjust_advance_towards_future_payments", nullable = true)
|
||||
private boolean adjustAdvanceTowardsFuturePayments;
|
||||
|
||||
protected DepositRecurringDetail() {
|
||||
//
|
||||
}
|
||||
|
||||
public static DepositRecurringDetail createFrom(final boolean isMandatoryDeposit, boolean allowWithdrawal,
|
||||
boolean adjustAdvanceTowardsFuturePayments) {
|
||||
|
||||
return new DepositRecurringDetail(isMandatoryDeposit, allowWithdrawal, adjustAdvanceTowardsFuturePayments);
|
||||
}
|
||||
|
||||
private DepositRecurringDetail(final boolean isMandatoryDeposit, boolean allowWithdrawal, boolean adjustAdvanceTowardsFuturePayments) {
|
||||
this.isMandatoryDeposit = isMandatoryDeposit;
|
||||
this.allowWithdrawal = allowWithdrawal;
|
||||
this.adjustAdvanceTowardsFuturePayments = adjustAdvanceTowardsFuturePayments;
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(10);
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(isMandatoryDepositParamName, this.isMandatoryDeposit)) {
|
||||
final boolean newValue = command.booleanObjectValueOfParameterNamed(isMandatoryDepositParamName);
|
||||
actualChanges.put(isMandatoryDepositParamName, newValue);
|
||||
this.isMandatoryDeposit = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(allowWithdrawalParamName, this.allowWithdrawal)) {
|
||||
final boolean newValue = command.booleanObjectValueOfParameterNamed(allowWithdrawalParamName);
|
||||
actualChanges.put(allowWithdrawalParamName, newValue);
|
||||
this.allowWithdrawal = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(adjustAdvanceTowardsFuturePaymentsParamName, this.adjustAdvanceTowardsFuturePayments)) {
|
||||
final boolean newValue = command.booleanObjectValueOfParameterNamed(adjustAdvanceTowardsFuturePaymentsParamName);
|
||||
actualChanges.put(adjustAdvanceTowardsFuturePaymentsParamName, newValue);
|
||||
this.adjustAdvanceTowardsFuturePayments = newValue;
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public boolean isMandatoryDeposit() {
|
||||
return this.isMandatoryDeposit;
|
||||
}
|
||||
|
||||
public boolean allowWithdrawal() {
|
||||
return this.allowWithdrawal;
|
||||
}
|
||||
|
||||
public boolean adjustAdvanceTowardsFuturePayments() {
|
||||
return this.adjustAdvanceTowardsFuturePayments;
|
||||
}
|
||||
|
||||
public DepositRecurringDetail copy() {
|
||||
return DepositRecurringDetail.createFrom(this.isMandatoryDeposit, this.allowWithdrawal, this.adjustAdvanceTowardsFuturePayments);
|
||||
}
|
||||
}
|
||||
+266
@@ -0,0 +1,266 @@
|
||||
/**
|
||||
* 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 static org.apache.fineract.portfolio.savings.DepositsApiConstants.inMultiplesOfDepositTermParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.inMultiplesOfDepositTermTypeIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.maxDepositTermParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.maxDepositTermTypeIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.minDepositTermParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.minDepositTermTypeIdParamName;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
import org.apache.fineract.portfolio.savings.service.SavingsEnumerations;
|
||||
|
||||
/**
|
||||
* DepositTermDetail encapsulates all the details of a {@link FixedDepositProduct} that are also used and persisted by a
|
||||
* {@link FixedDepositAccount}.
|
||||
*/
|
||||
@Embeddable
|
||||
public class DepositTermDetail {
|
||||
|
||||
@Column(name = "min_deposit_term", nullable = true)
|
||||
private Integer minDepositTerm;
|
||||
|
||||
@Column(name = "max_deposit_term", nullable = true)
|
||||
private Integer maxDepositTerm;
|
||||
|
||||
@Column(name = "min_deposit_term_type_enum", nullable = true)
|
||||
private Integer minDepositTermType;
|
||||
|
||||
@Column(name = "max_deposit_term_type_enum", nullable = true)
|
||||
private Integer maxDepositTermType;
|
||||
|
||||
@Column(name = "in_multiples_of_deposit_term", nullable = true)
|
||||
private Integer inMultiplesOfDepositTerm;
|
||||
|
||||
@Column(name = "in_multiples_of_deposit_term_type_enum", nullable = true)
|
||||
private Integer inMultiplesOfDepositTermType;
|
||||
|
||||
public static DepositTermDetail createFrom(final Integer minDepositTerm, final Integer maxDepositTerm,
|
||||
final SavingsPeriodFrequencyType minDepositTermType, final SavingsPeriodFrequencyType maxDepositTermType,
|
||||
final Integer inMultiplesOfDepositTerm, final SavingsPeriodFrequencyType inMultiplesOfDepositTermType) {
|
||||
|
||||
return new DepositTermDetail(minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm,
|
||||
inMultiplesOfDepositTermType);
|
||||
}
|
||||
|
||||
protected DepositTermDetail() {
|
||||
//
|
||||
}
|
||||
|
||||
private DepositTermDetail(final Integer minDepositTerm, final Integer maxDepositTerm,
|
||||
final SavingsPeriodFrequencyType minDepositTermType, final SavingsPeriodFrequencyType maxDepositTermType,
|
||||
final Integer inMultiplesOfDepositTerm, final SavingsPeriodFrequencyType inMultiplesOfDepositTermType) {
|
||||
this.minDepositTerm = minDepositTerm;
|
||||
this.maxDepositTerm = maxDepositTerm;
|
||||
this.minDepositTermType = (minDepositTermType == null) ? null : minDepositTermType.getValue();
|
||||
this.maxDepositTermType = (maxDepositTermType == null) ? null : maxDepositTermType.getValue();
|
||||
this.inMultiplesOfDepositTerm = inMultiplesOfDepositTerm;
|
||||
this.inMultiplesOfDepositTermType = (inMultiplesOfDepositTermType == null) ? null : inMultiplesOfDepositTermType.getValue();
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command, final DataValidatorBuilder baseDataValidator) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(10);
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(minDepositTermParamName, this.minDepositTerm)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(minDepositTermParamName);
|
||||
actualChanges.put(minDepositTermParamName, newValue);
|
||||
this.minDepositTerm = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(maxDepositTermParamName, this.maxDepositTerm)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(maxDepositTermParamName);
|
||||
actualChanges.put(maxDepositTermParamName, newValue);
|
||||
this.maxDepositTerm = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(minDepositTermTypeIdParamName, this.minDepositTermType)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(minDepositTermTypeIdParamName);
|
||||
actualChanges.put(minDepositTermTypeIdParamName, SavingsEnumerations.depositTermFrequencyType(newValue));
|
||||
this.minDepositTermType = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(maxDepositTermTypeIdParamName, this.maxDepositTermType)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(maxDepositTermTypeIdParamName);
|
||||
actualChanges.put(maxDepositTermTypeIdParamName, SavingsEnumerations.depositTermFrequencyType(newValue));
|
||||
this.maxDepositTermType = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(inMultiplesOfDepositTermParamName, this.inMultiplesOfDepositTerm)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(inMultiplesOfDepositTermParamName);
|
||||
actualChanges.put(inMultiplesOfDepositTermParamName, newValue);
|
||||
this.inMultiplesOfDepositTerm = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(inMultiplesOfDepositTermTypeIdParamName, this.inMultiplesOfDepositTermType)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(inMultiplesOfDepositTermTypeIdParamName);
|
||||
actualChanges.put(inMultiplesOfDepositTermTypeIdParamName, SavingsEnumerations.inMultiplesOfDepositTermFrequencyType(newValue));
|
||||
this.inMultiplesOfDepositTermType = newValue;
|
||||
}
|
||||
|
||||
if (isMinDepositTermGreaterThanMaxDepositTerm()) {
|
||||
baseDataValidator.parameter(minDepositTermParamName).value(this.minDepositTerm).failWithCode(".greater.than.maxDepositTerm",
|
||||
this.minDepositTerm, this.maxDepositTerm);
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public boolean isMinDepositTermGreaterThanMaxDepositTerm() {
|
||||
if (this.minDepositTerm != null && this.maxDepositTerm != null) {
|
||||
final Integer minDepositInDays = this.convertToSafeDays(minDepositTerm, SavingsPeriodFrequencyType.fromInt(minDepositTermType));
|
||||
final Integer maxDepositInDays = this.convertToSafeDays(maxDepositTerm, SavingsPeriodFrequencyType.fromInt(maxDepositTermType));
|
||||
if (minDepositInDays.compareTo(maxDepositInDays) > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Integer minDepositTerm() {
|
||||
return this.minDepositTerm;
|
||||
}
|
||||
|
||||
public Integer maxDepositTerm() {
|
||||
return this.maxDepositTerm;
|
||||
}
|
||||
|
||||
public Integer minDepositTermType() {
|
||||
return this.minDepositTermType;
|
||||
}
|
||||
|
||||
public Integer maxDepositTermType() {
|
||||
return this.maxDepositTermType;
|
||||
}
|
||||
|
||||
public Integer inMultiplesOfDepositTerm() {
|
||||
return this.inMultiplesOfDepositTerm;
|
||||
}
|
||||
|
||||
public Integer inMultiplesOfDepositTermType() {
|
||||
return this.inMultiplesOfDepositTermType;
|
||||
}
|
||||
|
||||
public boolean isDepositBetweenMinAndMax(LocalDate depositStartDate, LocalDate depositEndDate) {
|
||||
return isEqualOrGreaterThanMin(depositStartDate, depositEndDate) && isEqualOrLessThanMax(depositStartDate, depositEndDate);
|
||||
}
|
||||
|
||||
public boolean isValidInMultiplesOfPeriod(final Integer depositPeriod, final SavingsPeriodFrequencyType depositPeriodFrequencyType) {
|
||||
|
||||
boolean isValidInMultiplesOfPeriod = true;
|
||||
final Integer depositPeriodInDays = this.convertToSafeDays(depositPeriod, depositPeriodFrequencyType);
|
||||
if (this.inMultiplesOfDepositTerm() != null) {
|
||||
final Integer inMultiplesOfInDays = this.convertToSafeDays(this.inMultiplesOfDepositTerm(),
|
||||
SavingsPeriodFrequencyType.fromInt(this.inMultiplesOfDepositTermType()));
|
||||
final Integer minDepositInDays = this.convertToSafeDays(minDepositTerm, SavingsPeriodFrequencyType.fromInt(minDepositTermType));
|
||||
if (inMultiplesOfInDays != 0) {
|
||||
isValidInMultiplesOfPeriod = ((depositPeriodInDays - minDepositInDays) % inMultiplesOfInDays == 0);
|
||||
}
|
||||
}
|
||||
|
||||
return isValidInMultiplesOfPeriod;
|
||||
}
|
||||
|
||||
private boolean isEqualOrGreaterThanMin(LocalDate depositStartDate, LocalDate depositEndDate) {
|
||||
if (minDepositTerm() == null) {
|
||||
return true;
|
||||
}
|
||||
final SavingsPeriodFrequencyType periodFrequencyType = SavingsPeriodFrequencyType.fromInt(this.minDepositTermType());
|
||||
final Integer depositPeriod = depositPeriod(depositStartDate, depositEndDate, periodFrequencyType);
|
||||
return minDepositTerm() == null || depositPeriod.compareTo(minDepositTerm()) >= 0;
|
||||
}
|
||||
|
||||
private boolean isEqualOrLessThanMax(LocalDate depositStartDate, LocalDate depositEndDate) {
|
||||
if (maxDepositTerm() == null) {
|
||||
return true;
|
||||
}
|
||||
final SavingsPeriodFrequencyType periodFrequencyType = SavingsPeriodFrequencyType.fromInt(this.maxDepositTermType());
|
||||
final Integer depositPeriod = depositPeriod(depositStartDate, depositEndDate, periodFrequencyType);
|
||||
return maxDepositTerm() == null || depositPeriod.compareTo(maxDepositTerm()) <= 0;
|
||||
}
|
||||
|
||||
public Integer depositPeriod(final LocalDate periodStartDate, final LocalDate periodEndDate,
|
||||
final SavingsPeriodFrequencyType periodFrequencyType) {
|
||||
Integer actualDepositPeriod = 0;
|
||||
|
||||
switch (periodFrequencyType) {
|
||||
case DAYS:
|
||||
actualDepositPeriod = Math.toIntExact(ChronoUnit.DAYS.between(periodStartDate, periodEndDate));
|
||||
break;
|
||||
case WEEKS:
|
||||
actualDepositPeriod = Math.toIntExact(ChronoUnit.WEEKS.between(periodStartDate, periodEndDate));
|
||||
break;
|
||||
case MONTHS:
|
||||
actualDepositPeriod = Math.toIntExact(ChronoUnit.MONTHS.between(periodStartDate, periodEndDate));
|
||||
break;
|
||||
case YEARS:
|
||||
actualDepositPeriod = Math.toIntExact(ChronoUnit.YEARS.between(periodStartDate, periodEndDate));
|
||||
break;
|
||||
case INVALID:
|
||||
actualDepositPeriod = 0;// default value
|
||||
break;
|
||||
}
|
||||
return actualDepositPeriod;
|
||||
}
|
||||
|
||||
private Integer convertToSafeDays(final Integer period, final SavingsPeriodFrequencyType periodFrequencyType) {
|
||||
Integer toDays = 0;
|
||||
switch (periodFrequencyType) {
|
||||
case DAYS:
|
||||
toDays = period;
|
||||
break;
|
||||
case WEEKS:
|
||||
toDays = period * 7;
|
||||
break;
|
||||
case MONTHS:
|
||||
toDays = period * 30;// converting to stard 30 days
|
||||
break;
|
||||
case YEARS:
|
||||
toDays = period * 365;
|
||||
break;
|
||||
case INVALID:
|
||||
toDays = 0;// default value
|
||||
break;
|
||||
}
|
||||
return toDays;
|
||||
}
|
||||
|
||||
public DepositTermDetail copy() {
|
||||
|
||||
final Integer minDepositTerm = this.minDepositTerm;
|
||||
final Integer maxDepositTerm = this.maxDepositTerm;
|
||||
final SavingsPeriodFrequencyType minDepositTermType = SavingsPeriodFrequencyType.fromInt(this.minDepositTermType);
|
||||
final SavingsPeriodFrequencyType maxDepositTermType = SavingsPeriodFrequencyType.fromInt(this.maxDepositTermType);
|
||||
final Integer inMultiplesOfDepositTerm = this.inMultiplesOfDepositTerm;
|
||||
final SavingsPeriodFrequencyType inMultiplesOfDepositTermType = SavingsPeriodFrequencyType
|
||||
.fromInt(this.inMultiplesOfDepositTermType());
|
||||
|
||||
return DepositTermDetail.createFrom(minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType,
|
||||
inMultiplesOfDepositTerm, inMultiplesOfDepositTermType);
|
||||
}
|
||||
}
|
||||
+346
@@ -0,0 +1,346 @@
|
||||
/**
|
||||
* 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 static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.deleteParamName;
|
||||
import static org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.idParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.FIXED_DEPOSIT_PRODUCT_RESOURCE_NAME;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.maxDepositTermParamName;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.DiscriminatorValue;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.JoinTable;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Transient;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||
import org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestRateChart;
|
||||
import org.apache.fineract.portfolio.interestratechart.service.InterestRateChartAssembler;
|
||||
import org.apache.fineract.portfolio.savings.DepositsApiConstants;
|
||||
import org.apache.fineract.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.apache.fineract.portfolio.tax.domain.TaxGroup;
|
||||
|
||||
@Entity
|
||||
@DiscriminatorValue("200")
|
||||
public class FixedDepositProduct extends SavingsProduct {
|
||||
|
||||
@OneToOne(mappedBy = "product", cascade = CascadeType.ALL)
|
||||
private DepositProductTermAndPreClosure productTermAndPreClosure;
|
||||
|
||||
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
@JoinTable(name = "m_deposit_product_interest_rate_chart", joinColumns = @JoinColumn(name = "deposit_product_id"), inverseJoinColumns = @JoinColumn(name = "interest_rate_chart_id", unique = true))
|
||||
protected Set<InterestRateChart> charts;
|
||||
|
||||
@Transient
|
||||
protected InterestRateChartAssembler chartAssembler;
|
||||
|
||||
protected FixedDepositProduct() {
|
||||
|
||||
}
|
||||
|
||||
public static FixedDepositProduct createNew(final String name, final String shortName, final String description,
|
||||
final MonetaryCurrency currency, final BigDecimal interestRate,
|
||||
final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
|
||||
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
|
||||
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final Integer lockinPeriodFrequency,
|
||||
final SavingsPeriodFrequencyType lockinPeriodFrequencyType, final AccountingRuleType accountingRuleType,
|
||||
final Set<Charge> charges, final DepositProductTermAndPreClosure productTermAndPreClosure, final Set<InterestRateChart> charts,
|
||||
BigDecimal minBalanceForInterestCalculation, boolean withHoldTax, TaxGroup taxGroup) {
|
||||
|
||||
final BigDecimal minRequiredOpeningBalance = null;
|
||||
final boolean withdrawalFeeApplicableForTransfer = false;
|
||||
final boolean allowOverdraft = false;
|
||||
final BigDecimal overdraftLimit = null;
|
||||
|
||||
return new FixedDepositProduct(name, shortName, description, currency, interestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges,
|
||||
productTermAndPreClosure, charts, allowOverdraft, overdraftLimit, minBalanceForInterestCalculation, withHoldTax, taxGroup);
|
||||
}
|
||||
|
||||
protected FixedDepositProduct(final String name, final String shortName, final String description, final MonetaryCurrency currency,
|
||||
final BigDecimal interestRate, final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
|
||||
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
|
||||
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||
final boolean withdrawalFeeApplicableForTransfer, final AccountingRuleType accountingRuleType, final Set<Charge> charges,
|
||||
final DepositProductTermAndPreClosure productTermAndPreClosure, final Set<InterestRateChart> charts,
|
||||
final boolean allowOverdraft, final BigDecimal overdraftLimit, final BigDecimal minBalanceForInterestCalculation,
|
||||
boolean withHoldTax, TaxGroup taxGroup) {
|
||||
|
||||
super(name, shortName, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges, allowOverdraft, overdraftLimit,
|
||||
minBalanceForInterestCalculation, withHoldTax, taxGroup);
|
||||
|
||||
if (charts != null) {
|
||||
this.charts = charts;
|
||||
}
|
||||
|
||||
this.productTermAndPreClosure = productTermAndPreClosure;
|
||||
}
|
||||
|
||||
public void addCharts(final Set<InterestRateChart> newCharts) {
|
||||
final Set<InterestRateChart> existingCharts = setOfCharts();
|
||||
existingCharts.addAll(newCharts);
|
||||
}
|
||||
|
||||
public void addChart(final InterestRateChart newChart) {
|
||||
final Set<InterestRateChart> existingCharts = setOfCharts();
|
||||
existingCharts.add(newChart);
|
||||
}
|
||||
|
||||
public Set<InterestRateChart> setOfCharts() {
|
||||
if (this.charts == null) {
|
||||
this.charts = new HashSet<>();
|
||||
}
|
||||
return this.charts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> update(final JsonCommand command) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(10);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(FIXED_DEPOSIT_PRODUCT_RESOURCE_NAME);
|
||||
|
||||
actualChanges.putAll(this.update(command, baseDataValidator));
|
||||
|
||||
validateDomainRules(baseDataValidator);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
protected Map<String, Object> update(final JsonCommand command, final DataValidatorBuilder baseDataValidator) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(10);
|
||||
|
||||
actualChanges.putAll(super.update(command));
|
||||
|
||||
if (this.productTermAndPreClosure != null) {
|
||||
actualChanges.putAll(this.productTermAndPreClosure.update(command, baseDataValidator));
|
||||
}
|
||||
|
||||
// update chart Slabs
|
||||
if (command.hasParameter(DepositsApiConstants.chartsParamName)) {
|
||||
updateCharts(command, actualChanges, baseDataValidator);
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
private void updateCharts(JsonCommand command, Map<String, Object> actualChanges, final DataValidatorBuilder baseDataValidator) {
|
||||
final Map<String, Object> deletedCharts = new HashMap<>();
|
||||
final Map<String, Object> chartsChanges = new HashMap<>();
|
||||
|
||||
if (command.hasParameter(DepositsApiConstants.chartsParamName)) {
|
||||
final JsonArray array = command.arrayOfParameterNamed(DepositsApiConstants.chartsParamName);
|
||||
if (array != null) {
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
final JsonObject chartElement = array.get(i).getAsJsonObject();
|
||||
JsonCommand chartCommand = JsonCommand.fromExistingCommand(command, chartElement);
|
||||
if (chartCommand.parameterExists(idParamName)) {
|
||||
final Long chartId = chartCommand.longValueOfParameterNamed(idParamName);
|
||||
final InterestRateChart chart = this.findChart(chartId);
|
||||
if (chart == null) {
|
||||
baseDataValidator.parameter(idParamName).value(chartId).failWithCode("no.chart.associated.with.id");
|
||||
} else if (chartCommand.parameterExists(deleteParamName)) {
|
||||
if (this.removeChart(chart)) {
|
||||
deletedCharts.put(idParamName, chartId);
|
||||
}
|
||||
} else {
|
||||
chart.update(chartCommand, chartsChanges, baseDataValidator, this.setOfCharts(), this.currency().getCode());
|
||||
}
|
||||
} else {
|
||||
// assemble chart
|
||||
final InterestRateChart newChart = this.chartAssembler.assembleFrom(chartElement, this.currency().getCode(),
|
||||
baseDataValidator);
|
||||
this.addChart(newChart);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this.validateCharts(baseDataValidator);
|
||||
|
||||
// add chart changes to actual changes list.
|
||||
if (!chartsChanges.isEmpty()) {
|
||||
actualChanges.put(InterestRateChartApiConstants.chartSlabs, chartsChanges);
|
||||
}
|
||||
|
||||
// add deleted chart to actual changes
|
||||
if (!deletedCharts.isEmpty()) {
|
||||
actualChanges.put("deletedChartSlabs", deletedCharts);
|
||||
}
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InterestRateChart findChart(Long chartId) {
|
||||
final Set<InterestRateChart> charts = setOfCharts();
|
||||
|
||||
for (InterestRateChart chart : charts) {
|
||||
if (chart.getId().equals(chartId)) {
|
||||
return chart;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean removeChart(InterestRateChart chart) {
|
||||
Set<InterestRateChart> charts = setOfCharts();
|
||||
return charts.remove(chart);
|
||||
}
|
||||
|
||||
public void setHelpers(final InterestRateChartAssembler chartAssembler) {
|
||||
this.chartAssembler = chartAssembler;
|
||||
}
|
||||
|
||||
public void validateCharts(final DataValidatorBuilder baseDataValidator) {
|
||||
final Set<InterestRateChart> charts = this.setOfCharts();
|
||||
for (InterestRateChart existingChart : charts) {
|
||||
this.validateChart(baseDataValidator, existingChart);
|
||||
}
|
||||
}
|
||||
|
||||
public void validateChart(final DataValidatorBuilder baseDataValidator, final InterestRateChart comparingChart) {
|
||||
final Set<InterestRateChart> charts = this.setOfCharts();
|
||||
for (InterestRateChart existingChart : charts) {
|
||||
if (!existingChart.equals(comparingChart)) {
|
||||
if (existingChart.chartFields().isOverlapping(comparingChart.chartFields())) {
|
||||
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.overlapping.from.and.end.dates",
|
||||
existingChart.getFromDate(), existingChart.getEndDate(), comparingChart.getFromDate(),
|
||||
comparingChart.getEndDate());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InterestRateChart applicableChart(final LocalDate target) {
|
||||
InterestRateChart applicableChart = null;
|
||||
if (this.charts != null) {
|
||||
for (InterestRateChart chart : this.charts) {
|
||||
if (chart.isApplicableChartFor(target)) {
|
||||
applicableChart = chart;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return applicableChart;
|
||||
}
|
||||
|
||||
public DepositProductTermAndPreClosure depositProductTermAndPreClosure() {
|
||||
return this.productTermAndPreClosure;
|
||||
}
|
||||
|
||||
public void validateInterestPostingAndCompoundingPeriodTypes(final DataValidatorBuilder baseDataValidator) {
|
||||
Map<SavingsPostingInterestPeriodType, List<SavingsCompoundingInterestPeriodType>> postingtoCompoundMap = new HashMap<>();
|
||||
postingtoCompoundMap.put(SavingsPostingInterestPeriodType.MONTHLY, Arrays.asList(new SavingsCompoundingInterestPeriodType[] {
|
||||
SavingsCompoundingInterestPeriodType.DAILY, SavingsCompoundingInterestPeriodType.MONTHLY }));
|
||||
|
||||
postingtoCompoundMap.put(SavingsPostingInterestPeriodType.QUATERLY,
|
||||
Arrays.asList(new SavingsCompoundingInterestPeriodType[] { SavingsCompoundingInterestPeriodType.DAILY,
|
||||
SavingsCompoundingInterestPeriodType.MONTHLY, SavingsCompoundingInterestPeriodType.QUATERLY }));
|
||||
|
||||
postingtoCompoundMap.put(SavingsPostingInterestPeriodType.BIANNUAL,
|
||||
Arrays.asList(new SavingsCompoundingInterestPeriodType[] { SavingsCompoundingInterestPeriodType.DAILY,
|
||||
SavingsCompoundingInterestPeriodType.MONTHLY, SavingsCompoundingInterestPeriodType.QUATERLY,
|
||||
SavingsCompoundingInterestPeriodType.BI_ANNUAL }));
|
||||
|
||||
postingtoCompoundMap.put(SavingsPostingInterestPeriodType.ANNUAL,
|
||||
Arrays.asList(new SavingsCompoundingInterestPeriodType[] { SavingsCompoundingInterestPeriodType.DAILY,
|
||||
SavingsCompoundingInterestPeriodType.MONTHLY, SavingsCompoundingInterestPeriodType.QUATERLY,
|
||||
SavingsCompoundingInterestPeriodType.BI_ANNUAL, SavingsCompoundingInterestPeriodType.ANNUAL }));
|
||||
|
||||
SavingsPostingInterestPeriodType savingsPostingInterestPeriodType = SavingsPostingInterestPeriodType
|
||||
.fromInt(interestPostingPeriodType);
|
||||
SavingsCompoundingInterestPeriodType savingsCompoundingInterestPeriodType = SavingsCompoundingInterestPeriodType
|
||||
.fromInt(interestCompoundingPeriodType);
|
||||
|
||||
if (postingtoCompoundMap.get(savingsPostingInterestPeriodType) == null
|
||||
|| !postingtoCompoundMap.get(savingsPostingInterestPeriodType).contains(savingsCompoundingInterestPeriodType)) {
|
||||
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("posting.period.type.is.less.than.compound.period.type",
|
||||
savingsPostingInterestPeriodType.name(), savingsCompoundingInterestPeriodType.name());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void validateDomainRules() {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(FIXED_DEPOSIT_PRODUCT_RESOURCE_NAME);
|
||||
validateDomainRules(baseDataValidator);
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
private void validateDomainRules(final DataValidatorBuilder baseDataValidator) {
|
||||
|
||||
final DepositTermDetail termDetails = this.depositProductTermAndPreClosure().depositTermDetail();
|
||||
final boolean isMinTermGreaterThanMax = termDetails.isMinDepositTermGreaterThanMaxDepositTerm();
|
||||
if (isMinTermGreaterThanMax) {
|
||||
final Integer maxTerm = termDetails.maxDepositTerm();
|
||||
baseDataValidator.reset().parameter(maxDepositTermParamName).value(maxTerm)
|
||||
.failWithCodeNoParameterAddedToErrorCode("max.term.lessthan.min.term");
|
||||
}
|
||||
|
||||
if (this.charts != null) {
|
||||
validateCharts(baseDataValidator);
|
||||
} else if (this.nominalAnnualInterestRate == null || this.nominalAnnualInterestRate.compareTo(BigDecimal.ZERO) == 0) {
|
||||
baseDataValidator.reset().parameter(DepositsApiConstants.nominalAnnualInterestRateParamName).value(nominalAnnualInterestRate)
|
||||
.failWithCodeNoParameterAddedToErrorCode("interest.chart.or.nominal.interest.rate.required");
|
||||
}
|
||||
|
||||
this.validateInterestPostingAndCompoundingPeriodTypes(baseDataValidator);
|
||||
}
|
||||
|
||||
}
|
||||
+34
@@ -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.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);
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* 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 jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Set;
|
||||
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 final 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() {}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* 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 static org.apache.fineract.portfolio.savings.DepositsApiConstants.RECURRING_DEPOSIT_PRODUCT_RESOURCE_NAME;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.maxDepositTermParamName;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.DiscriminatorValue;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||
import org.apache.fineract.portfolio.interestratechart.domain.InterestRateChart;
|
||||
import org.apache.fineract.portfolio.savings.DepositsApiConstants;
|
||||
import org.apache.fineract.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.apache.fineract.portfolio.tax.domain.TaxGroup;
|
||||
|
||||
@Entity
|
||||
@DiscriminatorValue("300")
|
||||
public class RecurringDepositProduct extends FixedDepositProduct {
|
||||
|
||||
@OneToOne(mappedBy = "product", cascade = CascadeType.ALL)
|
||||
private DepositProductRecurringDetail recurringDetail;
|
||||
|
||||
protected RecurringDepositProduct() {
|
||||
|
||||
}
|
||||
|
||||
public static RecurringDepositProduct createNew(final String name, final String shortName, final String description,
|
||||
final MonetaryCurrency currency, final BigDecimal interestRate,
|
||||
final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
|
||||
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
|
||||
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final Integer lockinPeriodFrequency,
|
||||
final SavingsPeriodFrequencyType lockinPeriodFrequencyType, final AccountingRuleType accountingRuleType,
|
||||
final Set<Charge> charges, final DepositProductTermAndPreClosure productTermAndPreClosure,
|
||||
final DepositProductRecurringDetail recurringDetail, final Set<InterestRateChart> charts,
|
||||
BigDecimal minBalanceForInterestCalculation, final TaxGroup taxGroup, final boolean withHoldTax) {
|
||||
|
||||
final BigDecimal minRequiredOpeningBalance = null;
|
||||
final boolean withdrawalFeeApplicableForTransfer = false;
|
||||
final boolean allowOverdraft = false;
|
||||
final BigDecimal overdraftLimit = null;
|
||||
|
||||
return new RecurringDepositProduct(name, shortName, description, currency, interestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges,
|
||||
productTermAndPreClosure, recurringDetail, charts, allowOverdraft, overdraftLimit, minBalanceForInterestCalculation,
|
||||
withHoldTax, taxGroup);
|
||||
}
|
||||
|
||||
protected RecurringDepositProduct(final String name, final String shortName, final String description, final MonetaryCurrency currency,
|
||||
final BigDecimal interestRate, final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
|
||||
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
|
||||
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||
final boolean withdrawalFeeApplicableForTransfer, final AccountingRuleType accountingRuleType, final Set<Charge> charges,
|
||||
final DepositProductTermAndPreClosure productTermAndPreClosure, final DepositProductRecurringDetail recurringDetail,
|
||||
final Set<InterestRateChart> charts, final boolean allowOverdraft, final BigDecimal overdraftLimit,
|
||||
final BigDecimal minBalanceForInterestCalculation, final boolean withHoldTax, final TaxGroup taxGroup) {
|
||||
|
||||
super(name, shortName, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges, productTermAndPreClosure,
|
||||
charts, allowOverdraft, overdraftLimit, minBalanceForInterestCalculation, withHoldTax, taxGroup);
|
||||
|
||||
this.recurringDetail = recurringDetail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> update(final JsonCommand command) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(10);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(RECURRING_DEPOSIT_PRODUCT_RESOURCE_NAME);
|
||||
|
||||
actualChanges.putAll(this.update(command, baseDataValidator));
|
||||
|
||||
validateDomainRules(baseDataValidator);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> update(final JsonCommand command, final DataValidatorBuilder baseDataValidator) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(10);
|
||||
|
||||
actualChanges.putAll(super.update(command, baseDataValidator));
|
||||
|
||||
if (this.recurringDetail != null) {
|
||||
actualChanges.putAll(this.recurringDetail.update(command));
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
public DepositProductRecurringDetail depositRecurringDetail() {
|
||||
return this.recurringDetail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateDomainRules() {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(RECURRING_DEPOSIT_PRODUCT_RESOURCE_NAME);
|
||||
|
||||
validateDomainRules(baseDataValidator);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
private void validateDomainRules(final DataValidatorBuilder baseDataValidator) {
|
||||
final DepositTermDetail termDetails = this.depositProductTermAndPreClosure().depositTermDetail();
|
||||
final boolean isMinTermGreaterThanMax = termDetails.isMinDepositTermGreaterThanMaxDepositTerm();
|
||||
if (isMinTermGreaterThanMax) {
|
||||
final Integer maxTerm = termDetails.maxDepositTerm();
|
||||
baseDataValidator.reset().parameter(maxDepositTermParamName).value(maxTerm)
|
||||
.failWithCodeNoParameterAddedToErrorCode("max.term.lessthan.min.term");
|
||||
}
|
||||
|
||||
if (this.charts != null) {
|
||||
validateCharts(baseDataValidator);
|
||||
} else if (this.nominalAnnualInterestRate == null || this.nominalAnnualInterestRate.compareTo(BigDecimal.ZERO) == 0) {
|
||||
baseDataValidator.reset().parameter(DepositsApiConstants.nominalAnnualInterestRateParamName).value(nominalAnnualInterestRate)
|
||||
.failWithCodeNoParameterAddedToErrorCode("interest.chart.or.nominal.interest.rate.required");
|
||||
}
|
||||
|
||||
this.validateInterestPostingAndCompoundingPeriodTypes(baseDataValidator);
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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 org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
public interface RecurringDepositProductRepository
|
||||
extends JpaRepository<RecurringDepositProduct, Long>, JpaSpecificationExecutor<RecurringDepositProduct> {
|
||||
//
|
||||
}
|
||||
+3862
File diff suppressed because it is too large
Load Diff
+919
@@ -0,0 +1,919 @@
|
||||
/**
|
||||
* 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 static org.apache.fineract.portfolio.savings.SavingsApiConstants.amountParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.dateFormatParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.feeIntervalParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.feeOnMonthDayParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.localeParamName;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.time.LocalDate;
|
||||
import java.time.MonthDay;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
|
||||
import org.apache.fineract.portfolio.charge.exception.SavingsAccountChargeWithoutMandatoryFieldException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author dv6
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "m_savings_account_charge")
|
||||
public class SavingsAccountCharge extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SavingsAccountCharge.class);
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "savings_account_id", referencedColumnName = "id", nullable = false)
|
||||
private SavingsAccount savingsAccount;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "charge_id", referencedColumnName = "id", nullable = false)
|
||||
private Charge charge;
|
||||
|
||||
@Column(name = "charge_time_enum", nullable = false)
|
||||
private Integer chargeTime;
|
||||
|
||||
@Column(name = "charge_due_date")
|
||||
private LocalDate dueDate;
|
||||
|
||||
@Column(name = "fee_on_month", nullable = true)
|
||||
private Integer feeOnMonth;
|
||||
|
||||
@Column(name = "fee_on_day", nullable = true)
|
||||
private Integer feeOnDay;
|
||||
|
||||
@Column(name = "fee_interval", nullable = true)
|
||||
private Integer feeInterval;
|
||||
|
||||
@Column(name = "charge_calculation_enum")
|
||||
private Integer chargeCalculation;
|
||||
|
||||
@Column(name = "free_withdrawal_count", nullable = true)
|
||||
private Integer freeWithdrawalCount;
|
||||
|
||||
@Column(name = "charge_reset_date", nullable = true)
|
||||
private LocalDate chargeResetDate;
|
||||
|
||||
@Column(name = "calculation_percentage", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal percentage;
|
||||
|
||||
// TODO AA: This field may not require for savings charges
|
||||
@Column(name = "calculation_on_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal amountPercentageAppliedTo;
|
||||
|
||||
@Column(name = "amount", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal amount;
|
||||
|
||||
@Column(name = "amount_paid_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal amountPaid;
|
||||
|
||||
@Column(name = "amount_waived_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal amountWaived;
|
||||
|
||||
@Column(name = "amount_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal amountWrittenOff;
|
||||
|
||||
@Column(name = "amount_outstanding_derived", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal amountOutstanding;
|
||||
|
||||
@Column(name = "is_penalty", nullable = false)
|
||||
private boolean penaltyCharge = false;
|
||||
|
||||
@Column(name = "is_paid_derived", nullable = false)
|
||||
private boolean paid = false;
|
||||
|
||||
@Column(name = "waived", nullable = false)
|
||||
private boolean waived = false;
|
||||
|
||||
@Column(name = "is_active", nullable = false)
|
||||
private boolean status = true;
|
||||
|
||||
@Column(name = "inactivated_on_date")
|
||||
private LocalDate inactivationDate;
|
||||
|
||||
public static SavingsAccountCharge createNewFromJson(final SavingsAccount savingsAccount, final Charge chargeDefinition,
|
||||
final JsonCommand command) {
|
||||
|
||||
BigDecimal amount = command.bigDecimalValueOfParameterNamed(amountParamName);
|
||||
final LocalDate dueDate = command.localDateValueOfParameterNamed(dueAsOfDateParamName);
|
||||
MonthDay feeOnMonthDay = command.extractMonthDayNamed(feeOnMonthDayParamName);
|
||||
Integer feeInterval = command.integerValueOfParameterNamed(feeIntervalParamName);
|
||||
final ChargeTimeType chargeTime = null;
|
||||
final ChargeCalculationType chargeCalculation = null;
|
||||
final boolean status = true;
|
||||
|
||||
// If these values is not sent as parameter, then derive from Charge
|
||||
// definition
|
||||
amount = (amount == null) ? chargeDefinition.getAmount() : amount;
|
||||
feeOnMonthDay = (feeOnMonthDay == null) ? chargeDefinition.getFeeOnMonthDay() : feeOnMonthDay;
|
||||
feeInterval = (feeInterval == null) ? chargeDefinition.getFeeInterval() : feeInterval;
|
||||
|
||||
return new SavingsAccountCharge(savingsAccount, chargeDefinition, amount, chargeTime, chargeCalculation, dueDate, status,
|
||||
feeOnMonthDay, feeInterval);
|
||||
}
|
||||
|
||||
public static SavingsAccountCharge createNewWithoutSavingsAccount(final Charge chargeDefinition, final BigDecimal amountPayable,
|
||||
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculation, final LocalDate dueDate, final boolean status,
|
||||
final MonthDay feeOnMonthDay, final Integer feeInterval) {
|
||||
return new SavingsAccountCharge(null, chargeDefinition, amountPayable, chargeTime, chargeCalculation, dueDate, status,
|
||||
feeOnMonthDay, feeInterval);
|
||||
}
|
||||
|
||||
protected SavingsAccountCharge() {
|
||||
//
|
||||
}
|
||||
|
||||
private SavingsAccountCharge(final SavingsAccount savingsAccount, final Charge chargeDefinition, final BigDecimal amount,
|
||||
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculation, final LocalDate dueDate, final boolean status,
|
||||
MonthDay feeOnMonthDay, final Integer feeInterval) {
|
||||
|
||||
this.savingsAccount = savingsAccount;
|
||||
this.charge = chargeDefinition;
|
||||
this.penaltyCharge = chargeDefinition.isPenalty();
|
||||
this.chargeTime = (chargeTime == null) ? chargeDefinition.getChargeTimeType() : chargeTime.getValue();
|
||||
|
||||
if (isOnSpecifiedDueDate()) {
|
||||
if (dueDate == null) {
|
||||
final String defaultUserMessage = "Savings Account charge is missing due date.";
|
||||
throw new SavingsAccountChargeWithoutMandatoryFieldException("savingsaccount.charge", dueAsOfDateParamName,
|
||||
defaultUserMessage, chargeDefinition.getId(), chargeDefinition.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (isAnnualFee() || isMonthlyFee()) {
|
||||
feeOnMonthDay = (feeOnMonthDay == null) ? chargeDefinition.getFeeOnMonthDay() : feeOnMonthDay;
|
||||
if (feeOnMonthDay == null) {
|
||||
final String defaultUserMessage = "Savings Account charge is missing due date.";
|
||||
throw new SavingsAccountChargeWithoutMandatoryFieldException("savingsaccount.charge", dueAsOfDateParamName,
|
||||
defaultUserMessage, chargeDefinition.getId(), chargeDefinition.getName());
|
||||
}
|
||||
|
||||
this.feeOnMonth = feeOnMonthDay.getMonthValue();
|
||||
this.feeOnDay = feeOnMonthDay.getDayOfMonth();
|
||||
|
||||
} else if (isWeeklyFee()) {
|
||||
if (dueDate == null) {
|
||||
final String defaultUserMessage = "Savings Account charge is missing due date.";
|
||||
throw new SavingsAccountChargeWithoutMandatoryFieldException("savingsaccount.charge", dueAsOfDateParamName,
|
||||
defaultUserMessage, chargeDefinition.getId(), chargeDefinition.getName());
|
||||
}
|
||||
/**
|
||||
* For Weekly fee feeOnDay is ISO standard day of the week. Monday=1, Tuesday=2
|
||||
*/
|
||||
this.feeOnDay = dueDate.get(ChronoField.DAY_OF_WEEK);
|
||||
} else {
|
||||
this.feeOnDay = null;
|
||||
this.feeOnMonth = null;
|
||||
this.feeInterval = null;
|
||||
}
|
||||
|
||||
if (isMonthlyFee() || isWeeklyFee()) {
|
||||
this.feeInterval = (feeInterval == null) ? chargeDefinition.feeInterval() : feeInterval;
|
||||
}
|
||||
|
||||
this.dueDate = dueDate;
|
||||
|
||||
this.chargeCalculation = chargeDefinition.getChargeCalculation();
|
||||
if (chargeCalculation != null) {
|
||||
this.chargeCalculation = chargeCalculation.getValue();
|
||||
}
|
||||
|
||||
BigDecimal chargeAmount = chargeDefinition.getAmount();
|
||||
if (amount != null) {
|
||||
chargeAmount = amount;
|
||||
}
|
||||
|
||||
final BigDecimal transactionAmount = new BigDecimal(0);
|
||||
|
||||
populateDerivedFields(transactionAmount, chargeAmount);
|
||||
|
||||
if (this.isWithdrawalFee() || this.isSavingsNoActivity()) {
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
this.paid = determineIfFullyPaid();
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public void resetPropertiesForRecurringFees() {
|
||||
if (isMonthlyFee() || isAnnualFee() || isWeeklyFee()) {
|
||||
// FIXME: AA: If charge is percentage of x amount then need to
|
||||
// update amount outstanding accordingly.
|
||||
// Right now annual and monthly charges supports charge calculation
|
||||
// type flat.
|
||||
this.amountOutstanding = this.amount;
|
||||
this.paid = false;// reset to false for recurring fee.
|
||||
this.waived = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void populateDerivedFields(final BigDecimal transactionAmount, final BigDecimal chargeAmount) {
|
||||
|
||||
switch (ChargeCalculationType.fromInt(this.chargeCalculation)) {
|
||||
case INVALID:
|
||||
this.percentage = null;
|
||||
this.amount = null;
|
||||
this.amountPercentageAppliedTo = null;
|
||||
this.amountPaid = null;
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
this.amountWaived = null;
|
||||
this.amountWrittenOff = null;
|
||||
break;
|
||||
case FLAT:
|
||||
this.percentage = null;
|
||||
this.amount = chargeAmount;
|
||||
this.amountPercentageAppliedTo = null;
|
||||
this.amountPaid = null;
|
||||
this.amountOutstanding = chargeAmount;
|
||||
this.amountWaived = null;
|
||||
this.amountWrittenOff = null;
|
||||
break;
|
||||
case PERCENT_OF_AMOUNT:
|
||||
this.percentage = chargeAmount;
|
||||
this.amountPercentageAppliedTo = transactionAmount;
|
||||
this.amount = percentageOf(this.amountPercentageAppliedTo, this.percentage);
|
||||
this.amountPaid = null;
|
||||
this.amountOutstanding = calculateOutstanding();
|
||||
this.amountWaived = null;
|
||||
this.amountWrittenOff = null;
|
||||
break;
|
||||
case PERCENT_OF_AMOUNT_AND_INTEREST:
|
||||
this.percentage = null;
|
||||
this.amount = null;
|
||||
this.amountPercentageAppliedTo = null;
|
||||
this.amountPaid = null;
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
this.amountWaived = null;
|
||||
this.amountWrittenOff = null;
|
||||
break;
|
||||
case PERCENT_OF_INTEREST:
|
||||
this.percentage = null;
|
||||
this.amount = null;
|
||||
this.amountPercentageAppliedTo = null;
|
||||
this.amountPaid = null;
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
this.amountWaived = null;
|
||||
this.amountWrittenOff = null;
|
||||
break;
|
||||
case PERCENT_OF_DISBURSEMENT_AMOUNT:
|
||||
this.percentage = null;
|
||||
this.amount = null;
|
||||
this.amountPercentageAppliedTo = null;
|
||||
this.amountPaid = null;
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
this.amountWaived = null;
|
||||
this.amountWrittenOff = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void markAsFullyPaid() {
|
||||
this.amountPaid = this.amount;
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
this.paid = true;
|
||||
}
|
||||
|
||||
public void resetToOriginal(final MonetaryCurrency currency) {
|
||||
this.amountPaid = BigDecimal.ZERO;
|
||||
this.amountWaived = BigDecimal.ZERO;
|
||||
this.amountWrittenOff = BigDecimal.ZERO;
|
||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||
this.paid = false;
|
||||
this.waived = false;
|
||||
}
|
||||
|
||||
public void undoPayment(final MonetaryCurrency currency, final Money transactionAmount) {
|
||||
Money amountPaid = getAmountPaid(currency);
|
||||
amountPaid = amountPaid.minus(transactionAmount);
|
||||
this.amountPaid = amountPaid.getAmount();
|
||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||
|
||||
if (this.isWithdrawalFee()) {
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
}
|
||||
// to reset amount outstanding for annual and monthly fee
|
||||
resetPropertiesForRecurringFees();
|
||||
updateToPreviousDueDate();// reset annual and monthly due date.
|
||||
this.paid = false;
|
||||
this.status = true;
|
||||
}
|
||||
|
||||
public Money waive(final MonetaryCurrency currency) {
|
||||
Money amountWaivedToDate = Money.of(currency, this.amountWaived);
|
||||
Money amountOutstanding = Money.of(currency, this.amountOutstanding);
|
||||
this.amountWaived = amountWaivedToDate.plus(amountOutstanding).getAmount();
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
this.waived = true;
|
||||
|
||||
resetPropertiesForRecurringFees();
|
||||
updateNextDueDateForRecurringFees();
|
||||
|
||||
return amountOutstanding;
|
||||
}
|
||||
|
||||
public void undoWaiver(final MonetaryCurrency currency, final Money transactionAmount) {
|
||||
Money amountWaived = getAmountWaived(currency);
|
||||
amountWaived = amountWaived.minus(transactionAmount);
|
||||
this.amountWaived = amountWaived.getAmount();
|
||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||
this.waived = false;
|
||||
this.status = true;
|
||||
|
||||
resetPropertiesForRecurringFees();
|
||||
updateToPreviousDueDate();
|
||||
}
|
||||
|
||||
public Money pay(final MonetaryCurrency currency, final Money amountPaid) {
|
||||
Money amountPaidToDate = Money.of(currency, this.amountPaid);
|
||||
Money amountOutstanding = Money.of(currency, this.amountOutstanding);
|
||||
amountPaidToDate = amountPaidToDate.plus(amountPaid);
|
||||
amountOutstanding = amountOutstanding.minus(amountPaid);
|
||||
this.amountPaid = amountPaidToDate.getAmount();
|
||||
this.amountOutstanding = amountOutstanding.getAmount();
|
||||
this.paid = determineIfFullyPaid();
|
||||
|
||||
if (BigDecimal.ZERO.compareTo(this.amountOutstanding) == 0) {
|
||||
// full outstanding is paid, update to next due date
|
||||
updateNextDueDateForRecurringFees();
|
||||
resetPropertiesForRecurringFees();
|
||||
}
|
||||
|
||||
return Money.of(currency, this.amountOutstanding);
|
||||
}
|
||||
|
||||
private BigDecimal calculateAmountOutstanding(final MonetaryCurrency currency) {
|
||||
return getAmount(currency).minus(getAmountWaived(currency)).minus(getAmountPaid(currency)).getAmount();
|
||||
}
|
||||
|
||||
public void update(final SavingsAccount savingsAccount) {
|
||||
this.savingsAccount = savingsAccount;
|
||||
}
|
||||
|
||||
public void update(final BigDecimal amount, final LocalDate dueDate, final MonthDay feeOnMonthDay, final Integer feeInterval) {
|
||||
final BigDecimal transactionAmount = BigDecimal.ZERO;
|
||||
if (dueDate != null) {
|
||||
this.dueDate = dueDate;
|
||||
if (isWeeklyFee()) {
|
||||
this.feeOnDay = dueDate.get(ChronoField.DAY_OF_WEEK);
|
||||
}
|
||||
}
|
||||
|
||||
if (feeOnMonthDay != null) {
|
||||
this.feeOnMonth = feeOnMonthDay.getMonthValue();
|
||||
this.feeOnDay = feeOnMonthDay.getDayOfMonth();
|
||||
}
|
||||
|
||||
if (feeInterval != null) {
|
||||
this.feeInterval = feeInterval;
|
||||
}
|
||||
|
||||
if (amount != null) {
|
||||
switch (ChargeCalculationType.fromInt(this.chargeCalculation)) {
|
||||
case INVALID:
|
||||
break;
|
||||
case FLAT:
|
||||
this.amount = amount;
|
||||
break;
|
||||
case PERCENT_OF_AMOUNT:
|
||||
this.percentage = amount;
|
||||
this.amountPercentageAppliedTo = transactionAmount;
|
||||
this.amount = percentageOf(this.amountPercentageAppliedTo, this.percentage);
|
||||
this.amountOutstanding = calculateOutstanding();
|
||||
break;
|
||||
case PERCENT_OF_AMOUNT_AND_INTEREST:
|
||||
this.percentage = amount;
|
||||
this.amount = null;
|
||||
this.amountPercentageAppliedTo = null;
|
||||
this.amountOutstanding = null;
|
||||
break;
|
||||
case PERCENT_OF_INTEREST:
|
||||
this.percentage = amount;
|
||||
this.amount = null;
|
||||
this.amountPercentageAppliedTo = null;
|
||||
this.amountOutstanding = null;
|
||||
break;
|
||||
case PERCENT_OF_DISBURSEMENT_AMOUNT:
|
||||
LOG.error("TODO Implement update ChargeCalculationType for PERCENT_OF_DISBURSEMENT_AMOUNT");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF_NONVIRTUAL") // https://issues.apache.org/jira/browse/FINERACT-987
|
||||
public Map<String, Object> update(final JsonCommand command) {
|
||||
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(7);
|
||||
|
||||
final String dateFormatAsInput = command.dateFormat();
|
||||
final String localeAsInput = command.locale();
|
||||
|
||||
if (command.isChangeInLocalDateParameterNamed(dueAsOfDateParamName, getDueDate())) {
|
||||
final String valueAsInput = command.stringValueOfParameterNamed(dueAsOfDateParamName);
|
||||
actualChanges.put(dueAsOfDateParamName, valueAsInput);
|
||||
actualChanges.put(dateFormatParamName, dateFormatAsInput);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
|
||||
this.dueDate = command.localDateValueOfParameterNamed(dueAsOfDateParamName);
|
||||
if (this.isWeeklyFee()) {
|
||||
this.feeOnDay = this.dueDate.get(ChronoField.DAY_OF_WEEK);
|
||||
}
|
||||
}
|
||||
|
||||
if (command.hasParameter(feeOnMonthDayParamName)) {
|
||||
final MonthDay monthDay = command.extractMonthDayNamed(feeOnMonthDayParamName);
|
||||
final String actualValueEntered = command.stringValueOfParameterNamed(feeOnMonthDayParamName);
|
||||
final Integer dayOfMonthValue = monthDay.getDayOfMonth();
|
||||
if (!this.feeOnDay.equals(dayOfMonthValue)) {
|
||||
actualChanges.put(feeOnMonthDayParamName, actualValueEntered);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.feeOnDay = dayOfMonthValue;
|
||||
}
|
||||
|
||||
final Integer monthOfYear = monthDay.getMonthValue();
|
||||
if (!this.feeOnMonth.equals(monthOfYear)) {
|
||||
actualChanges.put(feeOnMonthDayParamName, actualValueEntered);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.feeOnMonth = monthOfYear;
|
||||
}
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed(amountParamName, this.amount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(amountParamName);
|
||||
actualChanges.put(amountParamName, newValue);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
|
||||
switch (ChargeCalculationType.fromInt(this.chargeCalculation)) {
|
||||
case INVALID:
|
||||
break;
|
||||
case FLAT:
|
||||
this.amount = newValue;
|
||||
this.amountOutstanding = calculateOutstanding();
|
||||
break;
|
||||
case PERCENT_OF_AMOUNT:
|
||||
this.percentage = newValue;
|
||||
this.amountPercentageAppliedTo = null;
|
||||
this.amount = percentageOf(this.amountPercentageAppliedTo, this.percentage);
|
||||
this.amountOutstanding = calculateOutstanding();
|
||||
break;
|
||||
case PERCENT_OF_AMOUNT_AND_INTEREST:
|
||||
this.percentage = newValue;
|
||||
this.amount = null;
|
||||
this.amountPercentageAppliedTo = null;
|
||||
this.amountOutstanding = null;
|
||||
break;
|
||||
case PERCENT_OF_INTEREST:
|
||||
this.percentage = newValue;
|
||||
this.amount = null;
|
||||
this.amountPercentageAppliedTo = null;
|
||||
this.amountOutstanding = null;
|
||||
break;
|
||||
case PERCENT_OF_DISBURSEMENT_AMOUNT:
|
||||
LOG.error("TODO Implement update ChargeCalculationType for PERCENT_OF_DISBURSEMENT_AMOUNT");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
private boolean isGreaterThanZero(final BigDecimal value) {
|
||||
return value.compareTo(BigDecimal.ZERO) > 0;
|
||||
}
|
||||
|
||||
public LocalDate getDueDate() {
|
||||
return this.dueDate;
|
||||
}
|
||||
|
||||
private boolean determineIfFullyPaid() {
|
||||
return BigDecimal.ZERO.compareTo(calculateOutstanding()) == 0;
|
||||
}
|
||||
|
||||
private BigDecimal calculateOutstanding() {
|
||||
|
||||
BigDecimal amountPaidLocal = BigDecimal.ZERO;
|
||||
if (this.amountPaid != null) {
|
||||
amountPaidLocal = this.amountPaid;
|
||||
}
|
||||
|
||||
BigDecimal amountWaivedLocal = BigDecimal.ZERO;
|
||||
if (this.amountWaived != null) {
|
||||
amountWaivedLocal = this.amountWaived;
|
||||
}
|
||||
|
||||
BigDecimal amountWrittenOffLocal = BigDecimal.ZERO;
|
||||
if (this.amountWrittenOff != null) {
|
||||
amountWrittenOffLocal = this.amountWrittenOff;
|
||||
}
|
||||
|
||||
final BigDecimal totalAccountedFor = amountPaidLocal.add(amountWaivedLocal).add(amountWrittenOffLocal);
|
||||
|
||||
return this.amount.subtract(totalAccountedFor);
|
||||
}
|
||||
|
||||
private BigDecimal percentageOf(final BigDecimal value, final BigDecimal percentage) {
|
||||
|
||||
BigDecimal percentageOf = BigDecimal.ZERO;
|
||||
|
||||
if (isGreaterThanZero(value)) {
|
||||
final MathContext mc = new MathContext(8, MoneyHelper.getRoundingMode());
|
||||
final BigDecimal multiplicand = percentage.divide(BigDecimal.valueOf(100L), mc);
|
||||
percentageOf = value.multiply(multiplicand, mc);
|
||||
}
|
||||
|
||||
return percentageOf;
|
||||
}
|
||||
|
||||
public BigDecimal amount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public BigDecimal amoutOutstanding() {
|
||||
return this.amountOutstanding;
|
||||
}
|
||||
|
||||
public boolean isFeeCharge() {
|
||||
return !this.penaltyCharge;
|
||||
}
|
||||
|
||||
public boolean isPenaltyCharge() {
|
||||
return this.penaltyCharge;
|
||||
}
|
||||
|
||||
public boolean isNotFullyPaid() {
|
||||
return !isPaid();
|
||||
}
|
||||
|
||||
public boolean isPaid() {
|
||||
return this.paid;
|
||||
}
|
||||
|
||||
public boolean isWaived() {
|
||||
return this.waived;
|
||||
}
|
||||
|
||||
public boolean isPaidOrPartiallyPaid(final MonetaryCurrency currency) {
|
||||
|
||||
final Money amountWaivedOrWrittenOff = getAmountWaived(currency).plus(getAmountWrittenOff(currency));
|
||||
return Money.of(currency, this.amountPaid).plus(amountWaivedOrWrittenOff).isGreaterThanZero();
|
||||
}
|
||||
|
||||
public Money getAmount(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amount);
|
||||
}
|
||||
|
||||
private Money getAmountPaid(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amountPaid);
|
||||
}
|
||||
|
||||
public Money getAmountWaived(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amountWaived);
|
||||
}
|
||||
|
||||
public Money getAmountWrittenOff(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amountWrittenOff);
|
||||
}
|
||||
|
||||
public Money getAmountOutstanding(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amountOutstanding);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param incrementBy
|
||||
* Amount used to pay off this charge
|
||||
* @return Actual amount paid on this charge
|
||||
*/
|
||||
public Money updatePaidAmountBy(final Money incrementBy) {
|
||||
|
||||
Money amountPaidToDate = Money.of(incrementBy.getCurrency(), this.amountPaid);
|
||||
final Money amountOutstanding = Money.of(incrementBy.getCurrency(), this.amountOutstanding);
|
||||
|
||||
Money amountPaidOnThisCharge = Money.zero(incrementBy.getCurrency());
|
||||
if (incrementBy.isGreaterThanOrEqualTo(amountOutstanding)) {
|
||||
amountPaidOnThisCharge = amountOutstanding;
|
||||
amountPaidToDate = amountPaidToDate.plus(amountOutstanding);
|
||||
this.amountPaid = amountPaidToDate.getAmount();
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
} else {
|
||||
amountPaidOnThisCharge = incrementBy;
|
||||
amountPaidToDate = amountPaidToDate.plus(incrementBy);
|
||||
this.amountPaid = amountPaidToDate.getAmount();
|
||||
|
||||
final Money amountExpected = Money.of(incrementBy.getCurrency(), this.amount);
|
||||
this.amountOutstanding = amountExpected.minus(amountPaidToDate).getAmount();
|
||||
}
|
||||
|
||||
this.paid = determineIfFullyPaid();
|
||||
|
||||
return amountPaidOnThisCharge;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return this.charge.getName();
|
||||
}
|
||||
|
||||
public String currencyCode() {
|
||||
return this.charge.getCurrencyCode();
|
||||
}
|
||||
|
||||
public Charge getCharge() {
|
||||
return this.charge;
|
||||
}
|
||||
|
||||
public boolean isEnableFreeWithdrawal() {
|
||||
return charge.isEnableFreeWithdrawal();
|
||||
}
|
||||
|
||||
public boolean isEnablePaymentType() {
|
||||
return charge.isEnablePaymentType();
|
||||
}
|
||||
|
||||
public Integer getFrequencyFreeWithdrawalCharge() { // number of times free withdrawal allowed
|
||||
return charge.getFrequencyFreeWithdrawalCharge();
|
||||
}
|
||||
|
||||
public Integer getRestartFrequency() { // numeric value of which numeric-period, count should restart
|
||||
return charge.getRestartFrequency();
|
||||
}
|
||||
|
||||
public Integer getRestartFrequencyEnum() { // enum day/week/month for restarting the count.
|
||||
return charge.getRestartFrequencyEnum();
|
||||
}
|
||||
|
||||
public Integer getFreeWithdrawalCount() {
|
||||
return freeWithdrawalCount;
|
||||
}
|
||||
|
||||
public void setFreeWithdrawalCount(Integer freeWithdrawalCount) {
|
||||
this.freeWithdrawalCount = freeWithdrawalCount;
|
||||
}
|
||||
|
||||
public LocalDate getResetChargeDate() {
|
||||
return chargeResetDate;
|
||||
}
|
||||
|
||||
public void setDiscountDueDate(final LocalDate date) {
|
||||
this.chargeResetDate = date;
|
||||
}
|
||||
|
||||
public SavingsAccount savingsAccount() {
|
||||
return this.savingsAccount;
|
||||
}
|
||||
|
||||
public boolean isOnSpecifiedDueDate() {
|
||||
return ChargeTimeType.fromInt(this.chargeTime).isOnSpecifiedDueDate();
|
||||
}
|
||||
|
||||
public boolean isSavingsActivation() {
|
||||
return ChargeTimeType.fromInt(this.chargeTime).isSavingsActivation();
|
||||
}
|
||||
|
||||
public boolean isSavingsNoActivity() {
|
||||
return ChargeTimeType.fromInt(this.chargeTime).isSavingsNoActivityFee();
|
||||
}
|
||||
|
||||
public boolean isSavingsClosure() {
|
||||
return ChargeTimeType.fromInt(this.chargeTime).isSavingsClosure();
|
||||
}
|
||||
|
||||
public boolean isWithdrawalFee() {
|
||||
return ChargeTimeType.fromInt(this.chargeTime).isWithdrawalFee();
|
||||
}
|
||||
|
||||
public boolean isOverdraftFee() {
|
||||
return ChargeTimeType.fromInt(this.chargeTime).isOverdraftFee();
|
||||
}
|
||||
|
||||
public boolean isAnnualFee() {
|
||||
return ChargeTimeType.fromInt(this.chargeTime).isAnnualFee();
|
||||
}
|
||||
|
||||
public boolean isMonthlyFee() {
|
||||
return ChargeTimeType.fromInt(this.chargeTime).isMonthlyFee();
|
||||
}
|
||||
|
||||
public boolean isWeeklyFee() {
|
||||
return ChargeTimeType.fromInt(this.chargeTime).isWeeklyFee();
|
||||
}
|
||||
|
||||
public boolean hasCurrencyCodeOf(final String matchingCurrencyCode) {
|
||||
if (this.currencyCode() == null || matchingCurrencyCode == null) {
|
||||
return false;
|
||||
}
|
||||
return this.currencyCode().equalsIgnoreCase(matchingCurrencyCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof SavingsAccountCharge)) {
|
||||
return false;
|
||||
}
|
||||
SavingsAccountCharge that = (SavingsAccountCharge) o;
|
||||
return (penaltyCharge == that.penaltyCharge) && (paid == that.paid) && (waived == that.waived) && (status == that.status)
|
||||
&& Objects.equals(savingsAccount, that.savingsAccount) && Objects.equals(charge, that.charge)
|
||||
&& Objects.equals(chargeTime, that.chargeTime) && DateUtils.isEqual(dueDate, that.dueDate)
|
||||
&& Objects.equals(feeOnMonth, that.feeOnMonth) && Objects.equals(feeOnDay, that.feeOnDay)
|
||||
&& Objects.equals(feeInterval, that.feeInterval) && Objects.equals(chargeCalculation, that.chargeCalculation)
|
||||
&& Objects.equals(percentage, that.percentage) && Objects.equals(amountPercentageAppliedTo, that.amountPercentageAppliedTo)
|
||||
&& Objects.equals(amount, that.amount) && Objects.equals(amountPaid, that.amountPaid)
|
||||
&& Objects.equals(amountWaived, that.amountWaived) && Objects.equals(amountWrittenOff, that.amountWrittenOff)
|
||||
&& Objects.equals(amountOutstanding, that.amountOutstanding) && DateUtils.isEqual(inactivationDate, that.inactivationDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(savingsAccount, charge, chargeTime, dueDate, feeOnMonth, feeOnDay, feeInterval, chargeCalculation, percentage,
|
||||
amountPercentageAppliedTo, amount, amountPaid, amountWaived, amountWrittenOff, amountOutstanding, penaltyCharge, paid,
|
||||
waived, status, inactivationDate);
|
||||
}
|
||||
|
||||
public BigDecimal calculateWithdralFeeAmount(@NotNull BigDecimal transactionAmount) {
|
||||
BigDecimal amountPaybale = BigDecimal.ZERO;
|
||||
if (ChargeCalculationType.fromInt(this.chargeCalculation).isFlat()) {
|
||||
amountPaybale = this.amount;
|
||||
} else if (ChargeCalculationType.fromInt(this.chargeCalculation).isPercentageOfAmount()) {
|
||||
amountPaybale = transactionAmount.multiply(this.percentage).divide(BigDecimal.valueOf(100L), MoneyHelper.getRoundingMode());
|
||||
}
|
||||
return amountPaybale;
|
||||
}
|
||||
|
||||
public BigDecimal updateWithdralFeeAmount(final BigDecimal transactionAmount) {
|
||||
return amountOutstanding = calculateWithdralFeeAmount(transactionAmount);
|
||||
}
|
||||
|
||||
public BigDecimal updateNoWithdrawalFee() {
|
||||
return amountOutstanding = BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
public void updateToNextDueDateFrom(final LocalDate startingDate) {
|
||||
if (isAnnualFee() || isMonthlyFee() || isWeeklyFee()) {
|
||||
this.dueDate = getNextDueDateFrom(startingDate);
|
||||
}
|
||||
}
|
||||
|
||||
public LocalDate getNextDueDateFrom(final LocalDate startingDate) {
|
||||
LocalDate nextDueLocalDate = null;
|
||||
if (isAnnualFee() || isMonthlyFee()) {
|
||||
nextDueLocalDate = startingDate.withMonth(this.feeOnMonth);
|
||||
nextDueLocalDate = setDayOfMonth(nextDueLocalDate);
|
||||
while (DateUtils.isBefore(nextDueLocalDate, startingDate)) {
|
||||
nextDueLocalDate = calculateNextDueDate(nextDueLocalDate);
|
||||
}
|
||||
} else if (isWeeklyFee()) {
|
||||
nextDueLocalDate = getDueDate();
|
||||
while (DateUtils.isBefore(nextDueLocalDate, startingDate)) {
|
||||
nextDueLocalDate = calculateNextDueDate(nextDueLocalDate);
|
||||
}
|
||||
} else {
|
||||
nextDueLocalDate = calculateNextDueDate(startingDate);
|
||||
}
|
||||
return nextDueLocalDate;
|
||||
}
|
||||
|
||||
private LocalDate calculateNextDueDate(final LocalDate date) {
|
||||
LocalDate nextDueLocalDate = null;
|
||||
if (isAnnualFee()) {
|
||||
nextDueLocalDate = date.withMonth(this.feeOnMonth).plusYears(1);
|
||||
nextDueLocalDate = setDayOfMonth(nextDueLocalDate);
|
||||
} else if (isMonthlyFee()) {
|
||||
nextDueLocalDate = date.plusMonths(this.feeInterval);
|
||||
nextDueLocalDate = setDayOfMonth(nextDueLocalDate);
|
||||
} else if (isWeeklyFee()) {
|
||||
nextDueLocalDate = date.plusWeeks(this.feeInterval);
|
||||
nextDueLocalDate = setDayOfWeek(nextDueLocalDate);
|
||||
}
|
||||
return nextDueLocalDate;
|
||||
}
|
||||
|
||||
private LocalDate setDayOfMonth(LocalDate nextDueLocalDate) {
|
||||
int maxDayOfMonth = nextDueLocalDate.lengthOfMonth();
|
||||
int newDayOfMonth = (this.feeOnDay.intValue() < maxDayOfMonth) ? this.feeOnDay : maxDayOfMonth;
|
||||
nextDueLocalDate = nextDueLocalDate.withDayOfMonth(newDayOfMonth);
|
||||
return nextDueLocalDate;
|
||||
}
|
||||
|
||||
private LocalDate setDayOfWeek(LocalDate nextDueLocalDate) {
|
||||
if (this.feeOnDay != nextDueLocalDate.get(ChronoField.DAY_OF_WEEK)) {
|
||||
nextDueLocalDate = nextDueLocalDate.with(ChronoField.DAY_OF_WEEK, this.feeOnDay);
|
||||
}
|
||||
return nextDueLocalDate;
|
||||
}
|
||||
|
||||
public void updateNextDueDateForRecurringFees() {
|
||||
if (isAnnualFee() || isMonthlyFee() || isWeeklyFee()) {
|
||||
this.dueDate = calculateNextDueDate(this.dueDate);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateToPreviousDueDate() {
|
||||
if (isAnnualFee() || isMonthlyFee() || isWeeklyFee()) {
|
||||
LocalDate nextDueLocalDate = dueDate;
|
||||
if (isAnnualFee()) {
|
||||
nextDueLocalDate = nextDueLocalDate.withMonth(this.feeOnMonth).minusYears(1);
|
||||
nextDueLocalDate = setDayOfMonth(nextDueLocalDate);
|
||||
} else if (isMonthlyFee()) {
|
||||
nextDueLocalDate = nextDueLocalDate.minusMonths(this.feeInterval);
|
||||
nextDueLocalDate = setDayOfMonth(nextDueLocalDate);
|
||||
} else if (isWeeklyFee()) {
|
||||
nextDueLocalDate = nextDueLocalDate.minusDays(7 * this.feeInterval);
|
||||
nextDueLocalDate = setDayOfWeek(nextDueLocalDate);
|
||||
}
|
||||
|
||||
this.dueDate = nextDueLocalDate;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean feeSettingsNotSet() {
|
||||
return !feeSettingsSet();
|
||||
}
|
||||
|
||||
public boolean feeSettingsSet() {
|
||||
return this.feeOnDay != null && this.feeOnMonth != null;
|
||||
}
|
||||
|
||||
public boolean isRecurringFee() {
|
||||
return isWeeklyFee() || isMonthlyFee() || isAnnualFee();
|
||||
}
|
||||
|
||||
public boolean isChargeIsDue(final LocalDate nextDueDate) {
|
||||
return DateUtils.isBefore(getDueDate(), nextDueDate);
|
||||
}
|
||||
|
||||
public boolean isChargeIsOverPaid(final LocalDate nextDueDate) {
|
||||
return DateUtils.isAfter(getDueDate(), nextDueDate) && MathUtil.isGreaterThanZero(amountPaid());
|
||||
}
|
||||
|
||||
private BigDecimal amountPaid() {
|
||||
return this.amountPaid;
|
||||
}
|
||||
|
||||
public void inactiavateCharge(final LocalDate inactivationOnDate) {
|
||||
this.inactivationDate = inactivationOnDate;
|
||||
this.status = false;
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
this.paid = true;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
public boolean isNotActive() {
|
||||
return !isActive();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is to identify the charges which can override the savings rules(for example if there is a minimum
|
||||
* enforced balance of 1000 on savings account with account balance of 1000, still these charges can be collected as
|
||||
* these charges are initiated by system and it can bring down the balance below the enforced minimum balance).
|
||||
*
|
||||
*/
|
||||
public boolean canOverriteSavingAccountRules() {
|
||||
return (!this.isSavingsActivation() && !this.isWithdrawalFee());
|
||||
}
|
||||
}
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
/**
|
||||
* 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 static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.amountParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargeCalculationTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargeIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargeTimeTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargesParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.feeIntervalParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.feeOnMonthDayParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.idParamName;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.MonthDay;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
|
||||
import org.apache.fineract.portfolio.charge.exception.ChargeCannotBeAppliedToException;
|
||||
import org.apache.fineract.portfolio.charge.exception.SavingsAccountChargeNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class SavingsAccountChargeAssembler {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final ChargeRepositoryWrapper chargeRepository;
|
||||
private final SavingsAccountChargeRepository savingsAccountChargeRepository;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountChargeAssembler(final FromJsonHelper fromApiJsonHelper, final ChargeRepositoryWrapper chargeRepository,
|
||||
final SavingsAccountChargeRepository savingsAccountChargeRepository) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
this.chargeRepository = chargeRepository;
|
||||
this.savingsAccountChargeRepository = savingsAccountChargeRepository;
|
||||
}
|
||||
|
||||
public Set<SavingsAccountCharge> fromParsedJson(final JsonElement element, final String productCurrencyCode) {
|
||||
|
||||
final Set<SavingsAccountCharge> savingsAccountCharges = new HashSet<>();
|
||||
|
||||
if (element.isJsonObject()) {
|
||||
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
||||
final String dateFormat = this.fromApiJsonHelper.extractDateFormatParameter(topLevelJsonElement);
|
||||
final String monthDayFormat = this.fromApiJsonHelper.extractMonthDayFormatParameter(topLevelJsonElement);
|
||||
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
|
||||
if (topLevelJsonElement.has(chargesParamName) && topLevelJsonElement.get(chargesParamName).isJsonArray()) {
|
||||
final JsonArray array = topLevelJsonElement.get(chargesParamName).getAsJsonArray();
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
|
||||
final JsonObject savingsChargeElement = array.get(i).getAsJsonObject();
|
||||
|
||||
final Long id = this.fromApiJsonHelper.extractLongNamed(idParamName, savingsChargeElement);
|
||||
final Long chargeId = this.fromApiJsonHelper.extractLongNamed(chargeIdParamName, savingsChargeElement);
|
||||
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalNamed(amountParamName, savingsChargeElement, locale);
|
||||
final Integer chargeTimeType = this.fromApiJsonHelper.extractIntegerNamed(chargeTimeTypeParamName, savingsChargeElement,
|
||||
locale);
|
||||
final Integer chargeCalculationType = this.fromApiJsonHelper.extractIntegerNamed(chargeCalculationTypeParamName,
|
||||
savingsChargeElement, locale);
|
||||
final LocalDate dueDate = this.fromApiJsonHelper.extractLocalDateNamed(dueAsOfDateParamName, savingsChargeElement,
|
||||
dateFormat, locale);
|
||||
|
||||
final MonthDay feeOnMonthDay = this.fromApiJsonHelper.extractMonthDayNamed(feeOnMonthDayParamName, savingsChargeElement,
|
||||
monthDayFormat, locale);
|
||||
final Integer feeInterval = this.fromApiJsonHelper.extractIntegerNamed(feeIntervalParamName, savingsChargeElement,
|
||||
locale);
|
||||
|
||||
if (id == null) {
|
||||
final Charge chargeDefinition = this.chargeRepository.findOneWithNotFoundDetection(chargeId);
|
||||
|
||||
if (!chargeDefinition.isSavingsCharge()) {
|
||||
final String errorMessage = "Charge with identifier " + chargeDefinition.getId()
|
||||
+ " cannot be applied to Savings product.";
|
||||
throw new ChargeCannotBeAppliedToException("savings.product", errorMessage, chargeDefinition.getId());
|
||||
}
|
||||
|
||||
ChargeTimeType chargeTime = null;
|
||||
if (chargeTimeType != null) {
|
||||
chargeTime = ChargeTimeType.fromInt(chargeTimeType);
|
||||
}
|
||||
|
||||
ChargeCalculationType chargeCalculation = null;
|
||||
if (chargeCalculationType != null) {
|
||||
chargeCalculation = ChargeCalculationType.fromInt(chargeCalculationType);
|
||||
}
|
||||
|
||||
final boolean status = true;
|
||||
final SavingsAccountCharge savingsAccountCharge = SavingsAccountCharge.createNewWithoutSavingsAccount(
|
||||
chargeDefinition, amount, chargeTime, chargeCalculation, dueDate, status, feeOnMonthDay, feeInterval);
|
||||
savingsAccountCharges.add(savingsAccountCharge);
|
||||
} else {
|
||||
final Long savingsAccountChargeId = id;
|
||||
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository
|
||||
.findById(savingsAccountChargeId)
|
||||
.orElseThrow(() -> new SavingsAccountChargeNotFoundException(savingsAccountChargeId));
|
||||
|
||||
savingsAccountCharge.update(amount, dueDate, feeOnMonthDay, feeInterval);
|
||||
|
||||
savingsAccountCharges.add(savingsAccountCharge);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.validateSavingsCharges(savingsAccountCharges, productCurrencyCode);
|
||||
return savingsAccountCharges;
|
||||
}
|
||||
|
||||
public Set<SavingsAccountCharge> fromSavingsProduct(final SavingsProduct savingsProduct) {
|
||||
|
||||
final Set<SavingsAccountCharge> savingsAccountCharges = new HashSet<>();
|
||||
Set<Charge> productCharges = savingsProduct.charges();
|
||||
for (Charge charge : productCharges) {
|
||||
ChargeTimeType chargeTime = null;
|
||||
if (charge.getChargeTimeType() != null) {
|
||||
chargeTime = ChargeTimeType.fromInt(charge.getChargeTimeType());
|
||||
}
|
||||
if (chargeTime != null && chargeTime.isOnSpecifiedDueDate()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ChargeCalculationType chargeCalculation = null;
|
||||
if (charge.getChargeCalculation() != null) {
|
||||
chargeCalculation = ChargeCalculationType.fromInt(charge.getChargeCalculation());
|
||||
}
|
||||
final boolean status = true;
|
||||
final SavingsAccountCharge savingsAccountCharge = SavingsAccountCharge.createNewWithoutSavingsAccount(charge,
|
||||
charge.getAmount(), chargeTime, chargeCalculation, null, status, charge.getFeeOnMonthDay(), charge.feeInterval());
|
||||
savingsAccountCharges.add(savingsAccountCharge);
|
||||
}
|
||||
return savingsAccountCharges;
|
||||
}
|
||||
|
||||
private void validateSavingsCharges(final Set<SavingsAccountCharge> charges, final String productCurrencyCode) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
boolean isOneWithdrawalPresent = false;
|
||||
boolean isOneAnnualPresent = false;
|
||||
for (SavingsAccountCharge charge : charges) {
|
||||
if (!charge.hasCurrencyCodeOf(productCurrencyCode)) {
|
||||
baseDataValidator.reset().parameter("currency").value(charge.getCharge().getId())
|
||||
.failWithCodeNoParameterAddedToErrorCode("currency.and.charge.currency.not.same");
|
||||
}
|
||||
|
||||
if (charge.isAnnualFee()) {
|
||||
if (isOneAnnualPresent) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("multiple.annual.fee.per.account.not.supported");
|
||||
}
|
||||
isOneAnnualPresent = true;
|
||||
}
|
||||
}
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* 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 jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.math.BigDecimal;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_savings_account_charge_paid_by")
|
||||
public class SavingsAccountChargePaidBy extends AbstractPersistableCustom {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "savings_account_transaction_id", nullable = false)
|
||||
private SavingsAccountTransaction savingsAccountTransaction;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "savings_account_charge_id", nullable = false)
|
||||
private SavingsAccountCharge savingsAccountCharge;
|
||||
|
||||
@Column(name = "amount", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal amount;
|
||||
|
||||
protected SavingsAccountChargePaidBy() {
|
||||
|
||||
}
|
||||
|
||||
public static SavingsAccountChargePaidBy instance(final SavingsAccountTransaction savingsAccountTransaction,
|
||||
final SavingsAccountCharge savingsAccountCharge, final BigDecimal amount) {
|
||||
return new SavingsAccountChargePaidBy(savingsAccountTransaction, savingsAccountCharge, amount);
|
||||
}
|
||||
|
||||
private SavingsAccountChargePaidBy(final SavingsAccountTransaction savingsAccountTransaction,
|
||||
final SavingsAccountCharge savingsAccountCharge, final BigDecimal amount) {
|
||||
this.savingsAccountTransaction = savingsAccountTransaction;
|
||||
this.savingsAccountCharge = savingsAccountCharge;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public SavingsAccountTransaction getSavingsAccountTransaction() {
|
||||
return this.savingsAccountTransaction;
|
||||
}
|
||||
|
||||
public void setSavingsAccountTransaction(final SavingsAccountTransaction savingsAccountTransaction) {
|
||||
this.savingsAccountTransaction = savingsAccountTransaction;
|
||||
}
|
||||
|
||||
public SavingsAccountCharge getSavingsAccountCharge() {
|
||||
return this.savingsAccountCharge;
|
||||
}
|
||||
|
||||
public void setSavingsAccountCharge(final SavingsAccountCharge savingsAccountCharge) {
|
||||
this.savingsAccountCharge = savingsAccountCharge;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public void setAmount(final BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public boolean isFeeCharge() {
|
||||
return (this.savingsAccountCharge == null) ? false : this.savingsAccountCharge.isFeeCharge();
|
||||
}
|
||||
|
||||
public boolean isPenaltyCharge() {
|
||||
return (this.savingsAccountCharge == null) ? false : this.savingsAccountCharge.isPenaltyCharge();
|
||||
}
|
||||
|
||||
public boolean canOverriteSavingAccountRules() {
|
||||
return (this.savingsAccountCharge == null) ? false : this.savingsAccountCharge.canOverriteSavingAccountRules();
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface SavingsAccountChargeRepository
|
||||
extends JpaRepository<SavingsAccountCharge, Long>, JpaSpecificationExecutor<SavingsAccountCharge> {
|
||||
|
||||
@Query("select sac from SavingsAccountCharge sac where sac.id =:id and sac.savingsAccount.id = :savingsAccountId")
|
||||
SavingsAccountCharge findByIdAndSavingsAccountId(@Param("id") Long id, @Param("savingsAccountId") Long savingsAccountId);
|
||||
|
||||
@Query("select sac from SavingsAccountCharge sac where sac.dueDate <=:transactionDate and sac.waived = false and sac.paid=false order by sac.dueDate")
|
||||
List<SavingsAccountCharge> findPendingCharges(@Param("transactionDate") LocalDate transactionDate);
|
||||
}
|
||||
+73
@@ -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.savings.domain;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.portfolio.charge.exception.SavingsAccountChargeNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Wrapper for {@link SavingsAccountChargeRepository} that adds NULL checking and Error handling capabilities
|
||||
* </p>
|
||||
*/
|
||||
@Service
|
||||
public class SavingsAccountChargeRepositoryWrapper {
|
||||
|
||||
private final SavingsAccountChargeRepository repository;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountChargeRepositoryWrapper(final SavingsAccountChargeRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public SavingsAccountCharge findOneWithNotFoundDetection(final Long id) {
|
||||
return this.repository.findById(id).orElseThrow(() -> new SavingsAccountChargeNotFoundException(id));
|
||||
}
|
||||
|
||||
public SavingsAccountCharge findOneWithNotFoundDetection(final Long id, final Long savingsAccountId) {
|
||||
final SavingsAccountCharge savingsAccountCharge = this.repository.findByIdAndSavingsAccountId(id, savingsAccountId);
|
||||
if (savingsAccountCharge == null) {
|
||||
throw new SavingsAccountChargeNotFoundException(id);
|
||||
}
|
||||
return savingsAccountCharge;
|
||||
}
|
||||
|
||||
public List<SavingsAccountCharge> findPendingCharges(final LocalDate transactionDate) {
|
||||
return this.repository.findPendingCharges(transactionDate);
|
||||
}
|
||||
|
||||
public void save(final SavingsAccountCharge savingsAccountCharge) {
|
||||
this.repository.save(savingsAccountCharge);
|
||||
}
|
||||
|
||||
public void save(final Iterable<SavingsAccountCharge> savingsAccountCharges) {
|
||||
this.repository.saveAll(savingsAccountCharges);
|
||||
}
|
||||
|
||||
public void saveAndFlush(final SavingsAccountCharge savingsAccountCharge) {
|
||||
this.repository.saveAndFlush(savingsAccountCharge);
|
||||
}
|
||||
|
||||
public void delete(final SavingsAccountCharge savingsAccountCharge) {
|
||||
this.repository.delete(savingsAccountCharge);
|
||||
}
|
||||
}
|
||||
+49
@@ -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.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.apache.fineract.portfolio.savings.SavingsTransactionBooleanValues;
|
||||
|
||||
public interface SavingsAccountDomainService {
|
||||
|
||||
SavingsAccountTransaction handleWithdrawal(SavingsAccount account, DateTimeFormatter fmt, LocalDate transactionDate,
|
||||
BigDecimal transactionAmount, PaymentDetail paymentDetail, SavingsTransactionBooleanValues transactionBooleanValues,
|
||||
boolean backdatedTxnsAllowedTill);
|
||||
|
||||
SavingsAccountTransaction handleDeposit(SavingsAccount account, DateTimeFormatter fmt, LocalDate transactionDate,
|
||||
BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean isAccountTransfer, boolean isRegularTransaction,
|
||||
boolean backdatedTxnsAllowedTill);
|
||||
|
||||
void postJournalEntries(SavingsAccount savingsAccount, Set<Long> existingTransactionIds, Set<Long> existingReversedTransactionIds,
|
||||
boolean backdatedTxnsAllowedTill);
|
||||
|
||||
SavingsAccountTransaction handleDividendPayout(SavingsAccount account, LocalDate transactionDate, BigDecimal transactionAmount,
|
||||
boolean backdatedTxnsAllowedTill);
|
||||
|
||||
SavingsAccountTransaction handleReversal(SavingsAccount account, List<SavingsAccountTransaction> savingsAccountTransactions,
|
||||
boolean backdatedTxnsAllowedTill);
|
||||
|
||||
SavingsAccountTransaction handleHold(SavingsAccount account, BigDecimal amount, LocalDate transactionDate, Boolean lienAllowed);
|
||||
}
|
||||
+341
@@ -0,0 +1,341 @@
|
||||
/**
|
||||
* 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 jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.Transient;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.savings.domain.interest.PostingPeriod;
|
||||
|
||||
/**
|
||||
* {@link SavingsAccountSummary} encapsulates all the summary details of a {@link SavingsAccount}.
|
||||
*/
|
||||
@Embeddable
|
||||
public final class SavingsAccountSummary {
|
||||
|
||||
@Column(name = "total_deposits_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalDeposits;
|
||||
|
||||
@Column(name = "total_withdrawals_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalWithdrawals;
|
||||
|
||||
@Column(name = "total_interest_earned_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalInterestEarned;
|
||||
|
||||
@Column(name = "total_interest_posted_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalInterestPosted;
|
||||
|
||||
@Column(name = "total_withdrawal_fees_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalWithdrawalFees;
|
||||
|
||||
@Column(name = "total_fees_charge_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalFeeCharge;
|
||||
|
||||
@Column(name = "total_penalty_charge_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPenaltyCharge;
|
||||
|
||||
@Column(name = "total_annual_fees_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalAnnualFees;
|
||||
|
||||
@Column(name = "account_balance_derived", scale = 6, precision = 19)
|
||||
private BigDecimal accountBalance = BigDecimal.ZERO;
|
||||
|
||||
// TODO: AA do we need this data to be persisted.
|
||||
@Transient
|
||||
private BigDecimal totalFeeChargesWaived = BigDecimal.ZERO;
|
||||
|
||||
@Transient
|
||||
private BigDecimal totalPenaltyChargesWaived = BigDecimal.ZERO;
|
||||
|
||||
@Column(name = "total_overdraft_interest_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalOverdraftInterestDerived;
|
||||
|
||||
@Column(name = "total_withhold_tax_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalWithholdTax;
|
||||
|
||||
@Column(name = "last_interest_calculation_date")
|
||||
private LocalDate lastInterestCalculationDate;
|
||||
|
||||
// Currently this represents the last interest posting date
|
||||
@Column(name = "interest_posted_till_date")
|
||||
private LocalDate interestPostedTillDate;
|
||||
|
||||
@Transient
|
||||
private BigDecimal runningBalanceOnInterestPostingTillDate = BigDecimal.ZERO;
|
||||
|
||||
SavingsAccountSummary() {
|
||||
//
|
||||
}
|
||||
|
||||
public void updateSummary(final MonetaryCurrency currency, final SavingsAccountTransactionSummaryWrapper wrapper,
|
||||
final List<SavingsAccountTransaction> transactions) {
|
||||
|
||||
this.totalDeposits = wrapper.calculateTotalDeposits(currency, transactions);
|
||||
this.totalWithdrawals = wrapper.calculateTotalWithdrawals(currency, transactions);
|
||||
this.totalInterestPosted = wrapper.calculateTotalInterestPosted(currency, transactions);
|
||||
this.totalWithdrawalFees = wrapper.calculateTotalWithdrawalFees(currency, transactions);
|
||||
this.totalAnnualFees = wrapper.calculateTotalAnnualFees(currency, transactions);
|
||||
this.totalFeeCharge = wrapper.calculateTotalFeesCharge(currency, transactions);
|
||||
this.totalPenaltyCharge = wrapper.calculateTotalPenaltyCharge(currency, transactions);
|
||||
this.totalFeeChargesWaived = wrapper.calculateTotalFeesChargeWaived(currency, transactions);
|
||||
this.totalPenaltyChargesWaived = wrapper.calculateTotalPenaltyChargeWaived(currency, transactions);
|
||||
this.totalOverdraftInterestDerived = wrapper.calculateTotalOverdraftInterest(currency, transactions);
|
||||
this.totalWithholdTax = wrapper.calculateTotalWithholdTaxWithdrawal(currency, transactions);
|
||||
|
||||
updateRunningBalanceAndPivotDate(false, transactions, null, null, null, currency);
|
||||
|
||||
this.accountBalance = Money.of(currency, this.totalDeposits).plus(this.totalInterestPosted).minus(this.totalWithdrawals)
|
||||
.minus(this.totalWithdrawalFees).minus(this.totalAnnualFees).minus(this.totalFeeCharge).minus(this.totalPenaltyCharge)
|
||||
.minus(totalOverdraftInterestDerived).minus(totalWithholdTax).getAmount();
|
||||
}
|
||||
|
||||
public void updateSummaryWithPivotConfig(final MonetaryCurrency currency, final SavingsAccountTransactionSummaryWrapper wrapper,
|
||||
final SavingsAccountTransaction transaction, final List<SavingsAccountTransaction> savingsAccountTransactions) {
|
||||
|
||||
if (transaction != null) {
|
||||
if (transaction.isReversalTransaction()) {
|
||||
return;
|
||||
}
|
||||
Money transactionAmount = Money.of(currency, transaction.getAmount());
|
||||
switch (transaction.getTransactionType()) {
|
||||
case DEPOSIT:
|
||||
if (transaction.isDepositAndNotReversed() || transaction.isDividendPayoutAndNotReversed()) {
|
||||
this.totalDeposits = Money.of(currency, this.totalDeposits).plus(transactionAmount).getAmount();
|
||||
this.accountBalance = Money.of(currency, this.accountBalance).plus(transactionAmount).getAmount();
|
||||
}
|
||||
break;
|
||||
case WITHDRAWAL:
|
||||
if (transaction.isWithdrawal() && transaction.isNotReversed()) {
|
||||
this.totalWithdrawals = Money.of(currency, this.totalWithdrawals).plus(transactionAmount).getAmount();
|
||||
this.accountBalance = Money.of(currency, this.accountBalance).minus(transactionAmount).getAmount();
|
||||
}
|
||||
break;
|
||||
case WITHDRAWAL_FEE:
|
||||
if (transaction.isWithdrawalFeeAndNotReversed() && transaction.isNotReversed()) {
|
||||
this.totalWithdrawalFees = Money.of(currency, this.totalWithdrawalFees).plus(transactionAmount).getAmount();
|
||||
this.totalFeeCharge = Money.of(currency, this.totalFeeCharge).plus(transactionAmount).getAmount();
|
||||
this.accountBalance = Money.of(currency, this.accountBalance).minus(transactionAmount).getAmount();
|
||||
}
|
||||
break;
|
||||
case ANNUAL_FEE:
|
||||
if (transaction.isAnnualFeeAndNotReversed() && transaction.isNotReversed()) {
|
||||
this.totalAnnualFees = Money.of(currency, this.totalAnnualFees).plus(transactionAmount).getAmount();
|
||||
this.totalFeeCharge = Money.of(currency, this.totalFeeCharge).plus(transactionAmount).getAmount();
|
||||
this.accountBalance = Money.of(currency, this.accountBalance).minus(transactionAmount).getAmount();
|
||||
}
|
||||
break;
|
||||
case WAIVE_CHARGES:
|
||||
if (transaction.isWaiveFeeChargeAndNotReversed()) {
|
||||
this.totalFeeChargesWaived = Money.of(currency, this.totalFeeChargesWaived).plus(transactionAmount.getAmount())
|
||||
.getAmount();
|
||||
} else if (transaction.isWaivePenaltyChargeAndNotReversed()) {
|
||||
this.totalPenaltyChargesWaived = Money.of(currency, this.totalPenaltyChargesWaived)
|
||||
.plus(transactionAmount.getAmount()).getAmount();
|
||||
}
|
||||
break;
|
||||
case PAY_CHARGE:
|
||||
if (transaction.isFeeChargeAndNotReversed()) {
|
||||
this.totalFeeCharge = Money.of(currency, this.totalFeeCharge).plus(transactionAmount).getAmount();
|
||||
} else if (transaction.isPenaltyChargeAndNotReversed()) {
|
||||
this.totalPenaltyCharge = Money.of(currency, this.totalPenaltyCharge).plus(transactionAmount).getAmount();
|
||||
}
|
||||
if (transaction.isFeeChargeAndNotReversed() || transaction.isPenaltyChargeAndNotReversed()) {
|
||||
this.accountBalance = Money.of(currency, this.accountBalance).minus(transactionAmount).getAmount();
|
||||
}
|
||||
break;
|
||||
case OVERDRAFT_INTEREST:
|
||||
if (transaction.isOverdraftInterestAndNotReversed()) {
|
||||
this.totalOverdraftInterestDerived = Money.of(currency, this.totalOverdraftInterestDerived).plus(transactionAmount)
|
||||
.getAmount();
|
||||
this.accountBalance = Money.of(currency, this.accountBalance).minus(transactionAmount).getAmount();
|
||||
}
|
||||
break;
|
||||
case WITHHOLD_TAX:
|
||||
if (transaction.isWithHoldTaxAndNotReversed()) {
|
||||
this.totalWithholdTax = Money.of(currency, this.totalWithholdTax).plus(transactionAmount).getAmount();
|
||||
this.accountBalance = Money.of(currency, this.accountBalance).minus(transactionAmount).getAmount();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// INTEREST_POSTING
|
||||
Money interestTotal = Money.zero(currency);
|
||||
Money withHoldTaxTotal = Money.zero(currency);
|
||||
Money overdraftInterestTotal = Money.zero(currency);
|
||||
this.totalDeposits = wrapper.calculateTotalDeposits(currency, savingsAccountTransactions);
|
||||
this.totalWithdrawals = wrapper.calculateTotalWithdrawals(currency, savingsAccountTransactions);
|
||||
|
||||
final HashMap<String, Money> map = updateRunningBalanceAndPivotDate(true, savingsAccountTransactions, interestTotal,
|
||||
overdraftInterestTotal, withHoldTaxTotal, currency);
|
||||
interestTotal = map.get("interestTotal");
|
||||
withHoldTaxTotal = map.get("withHoldTax");
|
||||
overdraftInterestTotal = map.get("overdraftInterestTotal");
|
||||
this.totalInterestPosted = interestTotal.getAmountDefaultedToNullIfZero();
|
||||
this.totalOverdraftInterestDerived = overdraftInterestTotal.getAmountDefaultedToNullIfZero();
|
||||
this.totalWithholdTax = withHoldTaxTotal.getAmountDefaultedToNullIfZero();
|
||||
|
||||
this.accountBalance = getRunningBalanceOnPivotDate();
|
||||
this.accountBalance = Money.of(currency, this.accountBalance).plus(Money.of(currency, this.totalDeposits))
|
||||
.plus(this.totalInterestPosted).minus(this.totalWithdrawals).minus(this.totalWithholdTax)
|
||||
.minus(this.totalOverdraftInterestDerived).getAmount();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private HashMap<String, Money> updateRunningBalanceAndPivotDate(final boolean backdatedTxnsAllowedTill,
|
||||
final List<SavingsAccountTransaction> savingsAccountTransactions, Money interestTotal, Money overdraftInterestTotal,
|
||||
Money withHoldTaxTotal, MonetaryCurrency currency) {
|
||||
boolean isUpdated = false;
|
||||
HashMap<String, Money> map = new HashMap<>();
|
||||
for (int i = savingsAccountTransactions.size() - 1; i >= 0; i--) {
|
||||
final SavingsAccountTransaction savingsAccountTransaction = savingsAccountTransactions.get(i);
|
||||
if (savingsAccountTransaction.isInterestPostingAndNotReversed() && !savingsAccountTransaction.isReversalTransaction()
|
||||
&& !isUpdated) {
|
||||
setInterestPostedTillDate(savingsAccountTransaction.getTransactionDate());
|
||||
isUpdated = true;
|
||||
if (!backdatedTxnsAllowedTill) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (savingsAccountTransaction.isOverdraftInterestAndNotReversed() && !savingsAccountTransaction.isReversalTransaction()
|
||||
&& !isUpdated) {
|
||||
setInterestPostedTillDate(savingsAccountTransaction.getTransactionDate());
|
||||
isUpdated = true;
|
||||
if (!backdatedTxnsAllowedTill) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
if (savingsAccountTransaction.isInterestPostingAndNotReversed() && savingsAccountTransaction.isNotReversed()
|
||||
&& !savingsAccountTransaction.isReversalTransaction()) {
|
||||
interestTotal = interestTotal.plus(savingsAccountTransaction.getAmount(currency));
|
||||
}
|
||||
if (savingsAccountTransaction.isOverdraftInterestAndNotReversed() && !savingsAccountTransaction.isReversalTransaction()) {
|
||||
overdraftInterestTotal = overdraftInterestTotal.plus(savingsAccountTransaction.getAmount());
|
||||
}
|
||||
if (savingsAccountTransaction.isWithHoldTaxAndNotReversed() && !savingsAccountTransaction.isReversalTransaction()) {
|
||||
withHoldTaxTotal = withHoldTaxTotal.plus(savingsAccountTransaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (backdatedTxnsAllowedTill) {
|
||||
map.put("interestTotal", interestTotal);
|
||||
map.put("withHoldTax", withHoldTaxTotal);
|
||||
map.put("overdraftInterestTotal", overdraftInterestTotal);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public void updateFromInterestPeriodSummaries(final MonetaryCurrency currency, final List<PostingPeriod> allPostingPeriods) {
|
||||
Money totalEarned = Money.zero(currency);
|
||||
for (final PostingPeriod period : allPostingPeriods) {
|
||||
Money interestEarned = period.interest();
|
||||
interestEarned = interestEarned == null ? Money.zero(currency) : interestEarned;
|
||||
totalEarned = totalEarned.plus(interestEarned);
|
||||
}
|
||||
this.lastInterestCalculationDate = DateUtils.getBusinessLocalDate();
|
||||
this.totalInterestEarned = totalEarned.getAmount();
|
||||
}
|
||||
|
||||
public boolean isLessThanOrEqualToAccountBalance(final Money amount) {
|
||||
final Money accountBalance = getAccountBalance(amount.getCurrency());
|
||||
return accountBalance.isGreaterThanOrEqualTo(amount);
|
||||
}
|
||||
|
||||
public Money getAccountBalance(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.accountBalance);
|
||||
}
|
||||
|
||||
public BigDecimal getAccountBalance() {
|
||||
return this.accountBalance;
|
||||
}
|
||||
|
||||
public void setAccountBalance(BigDecimal accountBalance) {
|
||||
this.accountBalance = accountBalance;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalInterestPosted() {
|
||||
return this.totalInterestPosted;
|
||||
}
|
||||
|
||||
public LocalDate getLastInterestCalculationDate() {
|
||||
return this.lastInterestCalculationDate;
|
||||
}
|
||||
|
||||
public void setInterestPostedTillDate(final LocalDate date) {
|
||||
this.interestPostedTillDate = date;
|
||||
}
|
||||
|
||||
public LocalDate getInterestPostedTillDate() {
|
||||
return this.interestPostedTillDate;
|
||||
}
|
||||
|
||||
public void setRunningBalanceOnPivotDate(final BigDecimal runningBalanceOnPivotDate) {
|
||||
this.runningBalanceOnInterestPostingTillDate = runningBalanceOnPivotDate;
|
||||
}
|
||||
|
||||
public BigDecimal getRunningBalanceOnPivotDate() {
|
||||
return this.runningBalanceOnInterestPostingTillDate;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalWithdrawals() {
|
||||
return this.totalWithdrawals;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalDeposits() {
|
||||
return this.totalDeposits;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalWithdrawalFees() {
|
||||
return this.totalWithdrawalFees;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalFeeCharge() {
|
||||
return this.totalFeeCharge;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalPenaltyCharge() {
|
||||
return this.totalPenaltyCharge;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalAnnualFees() {
|
||||
return this.totalAnnualFees;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalInterestEarned() {
|
||||
return this.totalInterestEarned;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalOverdraftInterestDerived() {
|
||||
return this.totalOverdraftInterestDerived;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalWithholdTax() {
|
||||
return this.totalWithholdTax;
|
||||
}
|
||||
}
|
||||
+884
@@ -0,0 +1,884 @@
|
||||
/**
|
||||
* 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 static org.apache.fineract.infrastructure.core.service.DateUtils.getSystemZoneId;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||
import org.apache.fineract.infrastructure.core.domain.LocalDateInterval;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.organisation.office.domain.Office;
|
||||
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.apache.fineract.portfolio.savings.SavingsAccountTransactionType;
|
||||
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionEnumData;
|
||||
import org.apache.fineract.portfolio.savings.domain.interest.EndOfDayBalance;
|
||||
import org.apache.fineract.portfolio.savings.domain.interest.SavingsAccountTransactionDetailsForPostingPeriod;
|
||||
import org.apache.fineract.portfolio.savings.service.SavingsEnumerations;
|
||||
import org.apache.fineract.portfolio.tax.domain.TaxComponent;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* All monetary transactions against a savings account are modelled through this entity.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "m_savings_account_transaction")
|
||||
public final class SavingsAccountTransaction extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "savings_account_id", referencedColumnName = "id", nullable = false)
|
||||
private SavingsAccount savingsAccount;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "office_id", nullable = false)
|
||||
private Office office;
|
||||
|
||||
@ManyToOne(cascade = CascadeType.ALL, optional = true)
|
||||
@JoinColumn(name = "payment_detail_id", nullable = true)
|
||||
private PaymentDetail paymentDetail;
|
||||
|
||||
@Column(name = "transaction_type_enum", nullable = false)
|
||||
private Integer typeOf;
|
||||
|
||||
@Column(name = "transaction_date", nullable = false)
|
||||
private LocalDate dateOf;
|
||||
|
||||
@Column(name = "amount", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal amount;
|
||||
|
||||
@Column(name = "is_reversed", nullable = false)
|
||||
private boolean reversed;
|
||||
|
||||
@Column(name = "running_balance_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal runningBalance;
|
||||
|
||||
@Column(name = "cumulative_balance_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal cumulativeBalance;
|
||||
|
||||
@Column(name = "balance_end_date_derived", nullable = true)
|
||||
private LocalDate balanceEndDate;
|
||||
|
||||
@Column(name = "balance_number_of_days_derived", nullable = true)
|
||||
private Integer balanceNumberOfDays;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "savingsAccountTransaction", orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private Set<SavingsAccountChargePaidBy> savingsAccountChargesPaid = new HashSet<>();
|
||||
|
||||
@Column(name = "overdraft_amount_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal overdraftAmount;
|
||||
|
||||
@Deprecated
|
||||
@Column(name = "created_date", nullable = true)
|
||||
private LocalDateTime createdDateToRemove;
|
||||
|
||||
@Column(name = "submitted_on_date", nullable = false)
|
||||
private LocalDate submittedOnDate;
|
||||
|
||||
@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, mappedBy = "savingsAccountTransaction")
|
||||
private List<SavingsAccountTransactionTaxDetails> taxDetails = new ArrayList<>();
|
||||
|
||||
@Column(name = "release_id_of_hold_amount", length = 20)
|
||||
private Long releaseIdOfHoldAmountTransaction;
|
||||
|
||||
@Column(name = "reason_for_block", nullable = true)
|
||||
private String reasonForBlock;
|
||||
|
||||
@Column(name = "is_reversal", nullable = false)
|
||||
private boolean reversalTransaction;
|
||||
|
||||
@Column(name = "original_transaction_id")
|
||||
private Long originalTxnId;
|
||||
|
||||
@Column(name = "is_lien_transaction")
|
||||
private Boolean lienTransaction;
|
||||
|
||||
@Column(name = "ref_no", nullable = true)
|
||||
private String refNo;
|
||||
|
||||
SavingsAccountTransaction() {}
|
||||
|
||||
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail,
|
||||
final Integer typeOf, final LocalDate transactionLocalDate, final BigDecimal amount, final boolean isReversed,
|
||||
final boolean isManualTransaction, final Boolean lienTransaction, final String refNo) {
|
||||
this.savingsAccount = savingsAccount;
|
||||
this.office = office;
|
||||
this.typeOf = typeOf;
|
||||
this.dateOf = transactionLocalDate;
|
||||
this.amount = amount;
|
||||
this.reversed = isReversed;
|
||||
this.paymentDetail = paymentDetail;
|
||||
this.createdDateToRemove = null; // #audit backward compatibility deprecated
|
||||
this.submittedOnDate = DateUtils.getBusinessLocalDate();
|
||||
this.isManualTransaction = isManualTransaction;
|
||||
this.lienTransaction = lienTransaction;
|
||||
this.refNo = refNo;
|
||||
}
|
||||
|
||||
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final Integer typeOf,
|
||||
final LocalDate transactionLocalDate, final Money amount, final boolean isReversed, final boolean isManualTransaction,
|
||||
final Boolean lienTransaction, final String refNo) {
|
||||
this(savingsAccount, office, null, typeOf, transactionLocalDate, amount, isReversed, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail,
|
||||
final Integer typeOf, final LocalDate transactionLocalDate, final Money amount, final boolean isReversed,
|
||||
final boolean isManualTransaction, final Boolean lienTransaction, final String refNo) {
|
||||
this(savingsAccount, office, paymentDetail, typeOf, transactionLocalDate, amount.getAmount(), isReversed, isManualTransaction,
|
||||
lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction deposit(final SavingsAccount savingsAccount, final Office office,
|
||||
final PaymentDetail paymentDetail, final LocalDate date, final Money amount, final String refNo) {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final Boolean lienTransaction = false;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.DEPOSIT.getValue(), date,
|
||||
amount, isReversed, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction deposit(final SavingsAccount savingsAccount, final Office office,
|
||||
final PaymentDetail paymentDetail, final LocalDate date, final Money amount,
|
||||
final SavingsAccountTransactionType savingsAccountTransactionType, final String refNo) {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final Boolean lienTransaction = false;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, savingsAccountTransactionType.getValue(), date, amount,
|
||||
isReversed, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction withdrawal(final SavingsAccount savingsAccount, final Office office,
|
||||
final PaymentDetail paymentDetail, final LocalDate date, final Money amount, final String refNo) {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final Boolean lienTransaction = false;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.WITHDRAWAL.getValue(),
|
||||
date, amount, isReversed, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction interestPosting(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
final Money amount, final boolean isManualTransaction) {
|
||||
final boolean isReversed = false;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.INTEREST_POSTING.getValue(), date,
|
||||
amount, isReversed, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction overdraftInterest(final SavingsAccount savingsAccount, final Office office,
|
||||
final LocalDate date, final Money amount, final boolean isManualTransaction) {
|
||||
final boolean isReversed = false;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.OVERDRAFT_INTEREST.getValue(), date,
|
||||
amount, isReversed, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction withdrawalFee(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
final Money amount, final String refNo) {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final Boolean lienTransaction = false;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.WITHDRAWAL_FEE.getValue(), date, amount,
|
||||
isReversed, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction annualFee(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
final Money amount) {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.ANNUAL_FEE.getValue(), date, amount,
|
||||
isReversed, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction charge(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
final Money amount) {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.PAY_CHARGE.getValue(), date, amount,
|
||||
isReversed, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction waiver(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
final Money amount) {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.WAIVE_CHARGES.getValue(), date, amount,
|
||||
isReversed, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction initiateTransfer(final SavingsAccount savingsAccount, final Office office,
|
||||
final LocalDate date) {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail,
|
||||
SavingsAccountTransactionType.INITIATE_TRANSFER.getValue(), date, savingsAccount.getSummary().getAccountBalance(),
|
||||
isReversed, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction approveTransfer(final SavingsAccount savingsAccount, final Office office,
|
||||
final LocalDate date) {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail,
|
||||
SavingsAccountTransactionType.APPROVE_TRANSFER.getValue(), date, savingsAccount.getSummary().getAccountBalance(),
|
||||
isReversed, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction withdrawTransfer(final SavingsAccount savingsAccount, final Office office,
|
||||
final LocalDate date) {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail,
|
||||
SavingsAccountTransactionType.WITHDRAW_TRANSFER.getValue(), date, savingsAccount.getSummary().getAccountBalance(),
|
||||
isReversed, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction withHoldTax(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
final Money amount, final Map<TaxComponent, BigDecimal> taxDetails) {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
SavingsAccountTransaction accountTransaction = new SavingsAccountTransaction(savingsAccount, office,
|
||||
SavingsAccountTransactionType.WITHHOLD_TAX.getValue(), date, amount, isReversed, isManualTransaction, lienTransaction,
|
||||
refNo);
|
||||
updateTaxDetails(taxDetails, accountTransaction);
|
||||
return accountTransaction;
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction escheat(final SavingsAccount savingsAccount, final LocalDate date,
|
||||
final boolean accountTransaction) {
|
||||
final boolean isReversed = false;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
final Boolean lienTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, savingsAccount.office(), paymentDetail,
|
||||
SavingsAccountTransactionType.ESCHEAT.getValue(), date, savingsAccount.getSummary().getAccountBalance(), isReversed,
|
||||
accountTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction copyTransaction(SavingsAccountTransaction accountTransaction) {
|
||||
return new SavingsAccountTransaction(accountTransaction.savingsAccount, accountTransaction.office, accountTransaction.paymentDetail,
|
||||
accountTransaction.typeOf, accountTransaction.getTransactionDate(), accountTransaction.amount, accountTransaction.reversed,
|
||||
accountTransaction.isManualTransaction, accountTransaction.lienTransaction, accountTransaction.refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction holdAmount(final SavingsAccount savingsAccount, final Office office,
|
||||
final PaymentDetail paymentDetail, final LocalDate date, final Money amount, final Boolean lienTransaction) {
|
||||
final boolean isReversed = false;
|
||||
final boolean isManualTransaction = false;
|
||||
final String refNo = null;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.AMOUNT_HOLD.getValue(),
|
||||
date, amount, isReversed, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction releaseAmount(SavingsAccountTransaction accountTransaction, LocalDate transactionDate) {
|
||||
return new SavingsAccountTransaction(accountTransaction.savingsAccount, accountTransaction.office, accountTransaction.paymentDetail,
|
||||
SavingsAccountTransactionType.AMOUNT_RELEASE.getValue(), transactionDate, accountTransaction.amount,
|
||||
accountTransaction.reversed, accountTransaction.isManualTransaction, accountTransaction.lienTransaction,
|
||||
accountTransaction.refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction reversal(SavingsAccountTransaction accountTransaction) {
|
||||
SavingsAccountTransaction sat = copyTransaction(accountTransaction);
|
||||
sat.reversed = false;
|
||||
sat.setReversalTransaction(true);
|
||||
sat.originalTxnId = accountTransaction.getId();
|
||||
return sat;
|
||||
}
|
||||
|
||||
public static void updateTaxDetails(final Map<TaxComponent, BigDecimal> taxDetails,
|
||||
final SavingsAccountTransaction accountTransaction) {
|
||||
if (taxDetails != null) {
|
||||
for (Map.Entry<TaxComponent, BigDecimal> mapEntry : taxDetails.entrySet()) {
|
||||
accountTransaction.getTaxDetails()
|
||||
.add(new SavingsAccountTransactionTaxDetails(accountTransaction, mapEntry.getKey(), mapEntry.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SavingsAccount getSavingsAccount() {
|
||||
return this.savingsAccount;
|
||||
}
|
||||
|
||||
public LocalDate getTransactionDate() {
|
||||
return this.dateOf;
|
||||
}
|
||||
|
||||
public LocalDate getEndOfBalanceDate() {
|
||||
return balanceEndDate;
|
||||
}
|
||||
|
||||
public boolean isReversed() {
|
||||
return this.reversed;
|
||||
}
|
||||
|
||||
public void reverse() {
|
||||
this.reversed = true;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public Money getAmount(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amount);
|
||||
}
|
||||
|
||||
public void setAmount(final Money amount) {
|
||||
this.amount = amount == null ? null : amount.getAmount();
|
||||
}
|
||||
|
||||
public BigDecimal getRunningBalance() {
|
||||
return this.runningBalance;
|
||||
}
|
||||
|
||||
public Money getRunningBalance(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.runningBalance);
|
||||
}
|
||||
|
||||
public void setRunningBalance(Money balance) {
|
||||
this.runningBalance = balance == null ? null : balance.getAmount();
|
||||
}
|
||||
|
||||
public boolean isManualTransaction() {
|
||||
return this.isManualTransaction;
|
||||
}
|
||||
|
||||
public Set<SavingsAccountChargePaidBy> getSavingsAccountChargesPaid() {
|
||||
return this.savingsAccountChargesPaid;
|
||||
}
|
||||
|
||||
public BigDecimal getOverdraftAmount() {
|
||||
return this.overdraftAmount;
|
||||
}
|
||||
|
||||
public Money getOverdraftAmount(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.overdraftAmount);
|
||||
}
|
||||
|
||||
void setOverdraftAmount(Money overdraftAmount) {
|
||||
this.overdraftAmount = overdraftAmount == null ? null : overdraftAmount.getAmount();
|
||||
}
|
||||
|
||||
public List<SavingsAccountTransactionTaxDetails> getTaxDetails() {
|
||||
return this.taxDetails;
|
||||
}
|
||||
|
||||
public Integer getTypeOf() {
|
||||
return this.typeOf;
|
||||
}
|
||||
|
||||
public SavingsAccountTransactionType getTransactionType() {
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf);
|
||||
}
|
||||
|
||||
public LocalDate getDateOf() {
|
||||
return this.dateOf;
|
||||
}
|
||||
|
||||
public String getRefNo() {
|
||||
return this.refNo;
|
||||
}
|
||||
|
||||
public PaymentDetail getPaymentDetail() {
|
||||
return this.paymentDetail;
|
||||
}
|
||||
|
||||
public void updateReleaseId(Long releaseId) {
|
||||
this.releaseIdOfHoldAmountTransaction = releaseId;
|
||||
}
|
||||
|
||||
public void updateReason(String reasonForBlock) {
|
||||
this.reasonForBlock = reasonForBlock;
|
||||
}
|
||||
|
||||
public Long getReleaseIdOfHoldAmountTransaction() {
|
||||
return this.releaseIdOfHoldAmountTransaction;
|
||||
}
|
||||
|
||||
public MonetaryCurrency getCurrency() {
|
||||
return savingsAccount == null ? null : savingsAccount.getCurrency();
|
||||
}
|
||||
|
||||
public Long getOfficeId() {
|
||||
return this.office.getId();
|
||||
}
|
||||
|
||||
public LocalDate getBalanceEndDate() {
|
||||
return this.balanceEndDate;
|
||||
}
|
||||
|
||||
public BigDecimal getCumulativeBalance() {
|
||||
return this.cumulativeBalance;
|
||||
}
|
||||
|
||||
public Integer getBalanceNumberOfDays() {
|
||||
return this.balanceNumberOfDays;
|
||||
}
|
||||
|
||||
public LocalDate getSubmittedOnDate() {
|
||||
return submittedOnDate;
|
||||
}
|
||||
|
||||
public boolean isReversalTransaction() {
|
||||
return reversalTransaction;
|
||||
}
|
||||
|
||||
void setReversalTransaction(boolean reversalTransaction) {
|
||||
this.reversalTransaction = reversalTransaction;
|
||||
}
|
||||
|
||||
public boolean isDeposit() {
|
||||
return getTransactionType().isDeposit();
|
||||
}
|
||||
|
||||
public boolean isDepositAndNotReversed() {
|
||||
return getTransactionType().isDeposit() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isDividendPayout() {
|
||||
return getTransactionType().isDividendPayout();
|
||||
}
|
||||
|
||||
public boolean isDividendPayoutAndNotReversed() {
|
||||
return getTransactionType().isDividendPayout() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isWithdrawal() {
|
||||
return getTransactionType().isWithdrawal();
|
||||
}
|
||||
|
||||
public boolean isPostInterestCalculationRequired() {
|
||||
return this.isDeposit() || this.isWithdrawal() || this.isChargeTransaction() || this.isDividendPayout() || this.isInterestPosting();
|
||||
}
|
||||
|
||||
public boolean isInterestPostingAndNotReversed() {
|
||||
return getTransactionType().isInterestPosting() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isInterestPosting() {
|
||||
return getTransactionType().isInterestPosting() || getTransactionType().isOverDraftInterestPosting();
|
||||
}
|
||||
|
||||
public boolean isWithdrawalFeeAndNotReversed() {
|
||||
return getTransactionType().isWithdrawalFee() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isWithdrawalFee() {
|
||||
return getTransactionType().isWithdrawalFee();
|
||||
}
|
||||
|
||||
public boolean isAnnualFeeAndNotReversed() {
|
||||
return isAnnualFee() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isAnnualFee() {
|
||||
return getTransactionType().isAnnualFee();
|
||||
}
|
||||
|
||||
public boolean isNotReversed() {
|
||||
return !isReversed();
|
||||
}
|
||||
|
||||
public boolean isTransferInitiation() {
|
||||
return getTransactionType().isTransferInitiation();
|
||||
}
|
||||
|
||||
public boolean isTransferApproval() {
|
||||
return getTransactionType().isTransferApproval();
|
||||
}
|
||||
|
||||
public boolean isTransferRejection() {
|
||||
return getTransactionType().isTransferRejection();
|
||||
}
|
||||
|
||||
public boolean isTransferWithdrawal() {
|
||||
return getTransactionType().isTransferWithdrawal();
|
||||
}
|
||||
|
||||
public boolean isTransferRelatedTransaction() {
|
||||
return isTransferInitiation() || isTransferApproval() || isTransferRejection() || isTransferWithdrawal();
|
||||
}
|
||||
|
||||
public void zeroBalanceFields() {
|
||||
this.runningBalance = null;
|
||||
this.cumulativeBalance = null;
|
||||
this.balanceEndDate = null;
|
||||
this.balanceNumberOfDays = null;
|
||||
}
|
||||
|
||||
public void updateCumulativeBalanceAndDates(final MonetaryCurrency currency, final LocalDate endOfBalanceDate) {
|
||||
// balance end date should not be before transaction date
|
||||
if (endOfBalanceDate != null && DateUtils.isBefore(endOfBalanceDate, this.getTransactionDate())) {
|
||||
this.balanceEndDate = this.getTransactionDate();
|
||||
} else {
|
||||
this.balanceEndDate = endOfBalanceDate;
|
||||
}
|
||||
this.balanceNumberOfDays = LocalDateInterval.create(getTransactionDate(), endOfBalanceDate).daysInPeriodInclusiveOfEndDate();
|
||||
this.cumulativeBalance = Money.of(currency, this.runningBalance).multipliedBy(this.balanceNumberOfDays).getAmount();
|
||||
}
|
||||
|
||||
public boolean isAcceptableForDailyBalance(final LocalDateInterval interestPeriodInterval) {
|
||||
return isNotReversed() && interestPeriodInterval.contains(getTransactionDate()) && isABalanceForAtLeastOneDay();
|
||||
}
|
||||
|
||||
private boolean isABalanceForAtLeastOneDay() {
|
||||
return this.balanceNumberOfDays != null && this.balanceNumberOfDays > 0;
|
||||
}
|
||||
|
||||
public boolean hasNotAmount(final Money amountToCheck) {
|
||||
final Money transactionAmount = getAmount(amountToCheck.getCurrency());
|
||||
return transactionAmount.isNotEqualTo(amountToCheck);
|
||||
}
|
||||
|
||||
public Map<String, Object> toMapData(final String currencyCode) {
|
||||
final Map<String, Object> thisTransactionData = new LinkedHashMap<>();
|
||||
|
||||
final SavingsAccountTransactionEnumData transactionType = SavingsEnumerations.transactionType(this.typeOf);
|
||||
|
||||
thisTransactionData.put("id", getId());
|
||||
thisTransactionData.put("officeId", this.office.getId());
|
||||
thisTransactionData.put("type", transactionType);
|
||||
thisTransactionData.put("reversed", isReversed());
|
||||
thisTransactionData.put("date", getTransactionDate());
|
||||
thisTransactionData.put("currencyCode", currencyCode);
|
||||
thisTransactionData.put("amount", this.amount);
|
||||
thisTransactionData.put("overdraftAmount", this.overdraftAmount);
|
||||
|
||||
if (this.paymentDetail != null) {
|
||||
thisTransactionData.put("paymentTypeId", this.paymentDetail.getPaymentType().getId());
|
||||
}
|
||||
|
||||
/***
|
||||
* Sending data in a map, though in savings we currently expect a transaction to always repay a single charge
|
||||
* (or may repay a part of a single charge too)
|
||||
***/
|
||||
if (!this.savingsAccountChargesPaid.isEmpty()) {
|
||||
final List<Map<String, Object>> savingsChargesPaidData = new ArrayList<>();
|
||||
for (final SavingsAccountChargePaidBy chargePaidBy : this.savingsAccountChargesPaid) {
|
||||
final Map<String, Object> savingChargePaidData = new LinkedHashMap<>();
|
||||
savingChargePaidData.put("chargeId", chargePaidBy.getSavingsAccountCharge().getCharge().getId());
|
||||
savingChargePaidData.put("isPenalty", chargePaidBy.getSavingsAccountCharge().getCharge().isPenalty());
|
||||
savingChargePaidData.put("savingsChargeId", chargePaidBy.getSavingsAccountCharge().getId());
|
||||
savingChargePaidData.put("amount", chargePaidBy.getAmount());
|
||||
|
||||
savingsChargesPaidData.add(savingChargePaidData);
|
||||
}
|
||||
thisTransactionData.put("savingsChargesPaid", savingsChargesPaidData);
|
||||
}
|
||||
|
||||
if (!this.taxDetails.isEmpty()) {
|
||||
final List<Map<String, Object>> taxData = new ArrayList<>();
|
||||
for (final SavingsAccountTransactionTaxDetails taxDetails : this.taxDetails) {
|
||||
final Map<String, Object> taxDetailsData = new HashMap<>();
|
||||
taxDetailsData.put("amount", taxDetails.getAmount());
|
||||
if (taxDetails.getTaxComponent().getCreditAcount() != null) {
|
||||
taxDetailsData.put("creditAccountId", taxDetails.getTaxComponent().getCreditAcount().getId());
|
||||
}
|
||||
taxData.add(taxDetailsData);
|
||||
}
|
||||
thisTransactionData.put("taxDetails", taxData);
|
||||
}
|
||||
|
||||
return thisTransactionData;
|
||||
}
|
||||
|
||||
public boolean isBefore(final LocalDate date) {
|
||||
return DateUtils.isBefore(getTransactionDate(), date);
|
||||
}
|
||||
|
||||
public boolean isAfter(final LocalDate date) {
|
||||
return DateUtils.isAfter(getTransactionDate(), date);
|
||||
}
|
||||
|
||||
public boolean occursOn(final LocalDate date) {
|
||||
return DateUtils.isEqual(getTransactionDate(), date);
|
||||
}
|
||||
|
||||
public EndOfDayBalance toEndOfDayBalance(final LocalDateInterval periodInterval, final MonetaryCurrency currency) {
|
||||
final Money endOfDayBalance = Money.of(currency, this.runningBalance);
|
||||
final Money openingBalance = endOfDayBalance;
|
||||
|
||||
LocalDate balanceDate = periodInterval.startDate();
|
||||
|
||||
int numberOfDays = periodInterval.daysInPeriodInclusiveOfEndDate();
|
||||
if (periodInterval.contains(getTransactionDate())) {
|
||||
balanceDate = getTransactionDate();
|
||||
final LocalDateInterval newInterval = LocalDateInterval.create(getTransactionDate(), periodInterval.endDate());
|
||||
numberOfDays = newInterval.daysInPeriodInclusiveOfEndDate();
|
||||
}
|
||||
|
||||
return EndOfDayBalance.from(balanceDate, openingBalance, endOfDayBalance, numberOfDays);
|
||||
}
|
||||
|
||||
public EndOfDayBalance toEndOfDayBalance(final Money openingBalance, final LocalDate nextTransactionDate) {
|
||||
final MonetaryCurrency currency = openingBalance.getCurrency();
|
||||
Money endOfDayBalance = openingBalance.copy();
|
||||
if (isDeposit() || isDividendPayoutAndNotReversed()) {
|
||||
endOfDayBalance = openingBalance.plus(getAmount(currency));
|
||||
} else if (isWithdrawal() || isChargeTransactionAndNotReversed()) {
|
||||
endOfDayBalance = openingBalance.minus(getAmount(currency));
|
||||
}
|
||||
|
||||
int numberOfDays = LocalDateInterval.create(getTransactionDate(), nextTransactionDate).daysInPeriodInclusiveOfEndDate();
|
||||
if (!openingBalance.isEqualTo(endOfDayBalance) && numberOfDays > 1) {
|
||||
numberOfDays = numberOfDays - 1;
|
||||
}
|
||||
return EndOfDayBalance.from(getTransactionDate(), openingBalance, endOfDayBalance, numberOfDays);
|
||||
}
|
||||
|
||||
public EndOfDayBalance toEndOfDayBalance(final Money openingBalance) {
|
||||
final MonetaryCurrency currency = openingBalance.getCurrency();
|
||||
Money endOfDayBalance = openingBalance.copy();
|
||||
if (isDeposit() || isDividendPayoutAndNotReversed()) {
|
||||
endOfDayBalance = openingBalance.plus(getAmount(currency));
|
||||
} else if (isWithdrawal() || isChargeTransactionAndNotReversed()) {
|
||||
|
||||
if (openingBalance.isGreaterThanZero() || this.savingsAccount.allowOverdraft()) {
|
||||
endOfDayBalance = openingBalance.minus(getAmount(currency));
|
||||
} else {
|
||||
endOfDayBalance = getRunningBalance(currency);
|
||||
}
|
||||
}
|
||||
|
||||
return EndOfDayBalance.from(getTransactionDate(), openingBalance, endOfDayBalance, this.balanceNumberOfDays);
|
||||
}
|
||||
|
||||
public EndOfDayBalance toEndOfDayBalanceBoundedBy(final Money openingBalance, final LocalDateInterval boundedBy) {
|
||||
final MonetaryCurrency currency = openingBalance.getCurrency();
|
||||
Money endOfDayBalance = openingBalance.copy();
|
||||
|
||||
int numberOfDaysOfBalance = this.balanceNumberOfDays;
|
||||
|
||||
LocalDate balanceStartDate = getTransactionDate();
|
||||
LocalDate balanceEndDate = getEndOfBalanceDate();
|
||||
|
||||
if (DateUtils.isBefore(balanceStartDate, boundedBy.startDate())) {
|
||||
balanceStartDate = boundedBy.startDate();
|
||||
final LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
|
||||
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();
|
||||
} else {
|
||||
if (isDeposit() || isDividendPayoutAndNotReversed()) {
|
||||
// endOfDayBalance = openingBalance.plus(getAmount(currency));
|
||||
// if (endOfDayBalance.isLessThanZero()) {
|
||||
endOfDayBalance = endOfDayBalance.plus(getAmount(currency));
|
||||
// }
|
||||
} else if (isWithdrawal() || isChargeTransactionAndNotReversed()) {
|
||||
// endOfDayBalance = openingBalance.minus(getAmount(currency));
|
||||
if (endOfDayBalance.isGreaterThanZero() || this.savingsAccount.allowOverdraft()) {
|
||||
endOfDayBalance = endOfDayBalance.minus(getAmount(currency));
|
||||
} else {
|
||||
endOfDayBalance = getRunningBalance(currency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DateUtils.isAfter(balanceEndDate, boundedBy.endDate())) {
|
||||
balanceEndDate = boundedBy.endDate();
|
||||
final LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
|
||||
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();
|
||||
}
|
||||
|
||||
return EndOfDayBalance.from(balanceStartDate, openingBalance, endOfDayBalance, numberOfDaysOfBalance);
|
||||
}
|
||||
|
||||
public boolean isBalanceInExistencesForOneDayOrMore() {
|
||||
return this.balanceNumberOfDays != null && this.balanceNumberOfDays >= 1;
|
||||
}
|
||||
|
||||
public boolean fallsWithin(final LocalDateInterval periodInterval) {
|
||||
final LocalDateInterval balanceInterval = LocalDateInterval.create(getTransactionDate(), getEndOfBalanceDate());
|
||||
return periodInterval.contains(balanceInterval);
|
||||
}
|
||||
|
||||
public boolean spansAnyPortionOf(final LocalDateInterval periodInterval) {
|
||||
final LocalDateInterval balanceInterval = LocalDateInterval.create(getTransactionDate(), getEndOfBalanceDate());
|
||||
return balanceInterval.containsPortionOf(periodInterval);
|
||||
}
|
||||
|
||||
public boolean isIdentifiedBy(final Long transactionId) {
|
||||
return getId().equals(transactionId);
|
||||
}
|
||||
|
||||
public boolean isCredit() {
|
||||
return isCreditType() && !isReversed() && !isReversalTransaction();
|
||||
}
|
||||
|
||||
public boolean isCreditType() {
|
||||
return getTransactionType().isCredit();
|
||||
}
|
||||
|
||||
public boolean isDebit() {
|
||||
return isDebitType() && !isReversed() && !isReversalTransaction();
|
||||
}
|
||||
|
||||
public boolean isDebitType() {
|
||||
return getTransactionType().isDebit();
|
||||
}
|
||||
|
||||
public boolean isWithHoldTaxAndNotReversed() {
|
||||
return getTransactionType().isWithHoldTax() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isOverdraftInterestAndNotReversed() {
|
||||
return getTransactionType().isIncomeFromInterest() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isPayCharge() {
|
||||
return getTransactionType().isPayCharge();
|
||||
}
|
||||
|
||||
public boolean isChargeTransaction() {
|
||||
return getTransactionType().isChargeTransaction();
|
||||
}
|
||||
|
||||
public boolean isChargeTransactionAndNotReversed() {
|
||||
return getTransactionType().isChargeTransaction() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isWaiveCharge() {
|
||||
return getTransactionType().isWaiveCharge();
|
||||
}
|
||||
|
||||
public boolean isAmountOnHold() {
|
||||
return getTransactionType().isAmountOnHold();
|
||||
}
|
||||
|
||||
public boolean isAmountRelease() {
|
||||
return getTransactionType().isAmountRelease();
|
||||
}
|
||||
|
||||
private boolean canOverriteSavingAccountRules() {
|
||||
final SavingsAccountChargePaidBy chargePaidBy = getSavingsAccountChargePaidBy();
|
||||
return isChargeTransaction() && chargePaidBy != null && chargePaidBy.canOverriteSavingAccountRules();
|
||||
}
|
||||
|
||||
public boolean canProcessBalanceCheck() {
|
||||
return isDebit() && !canOverriteSavingAccountRules();
|
||||
}
|
||||
|
||||
public boolean isFeeCharge() {
|
||||
final SavingsAccountChargePaidBy chargePaidBy = getSavingsAccountChargePaidBy();
|
||||
return isPayCharge() && chargePaidBy != null && chargePaidBy.isFeeCharge();
|
||||
}
|
||||
|
||||
public boolean isPenaltyCharge() {
|
||||
final SavingsAccountChargePaidBy chargePaidBy = getSavingsAccountChargePaidBy();
|
||||
return isPayCharge() && chargePaidBy != null && chargePaidBy.isPenaltyCharge();
|
||||
}
|
||||
|
||||
public boolean isFeeChargeAndNotReversed() {
|
||||
return isFeeCharge() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isPenaltyChargeAndNotReversed() {
|
||||
return isPenaltyCharge() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isWaiveFeeCharge() {
|
||||
final SavingsAccountChargePaidBy chargePaidBy = getSavingsAccountChargePaidBy();
|
||||
return isWaiveCharge() && chargePaidBy != null && chargePaidBy.isFeeCharge();
|
||||
}
|
||||
|
||||
public boolean isWaivePenaltyCharge() {
|
||||
final SavingsAccountChargePaidBy chargePaidBy = getSavingsAccountChargePaidBy();
|
||||
return isWaiveCharge() && chargePaidBy != null && chargePaidBy.isPenaltyCharge();
|
||||
}
|
||||
|
||||
public boolean isWaiveFeeChargeAndNotReversed() {
|
||||
return isWaiveFeeCharge() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isWaivePenaltyChargeAndNotReversed() {
|
||||
return isWaivePenaltyCharge() && isNotReversed();
|
||||
}
|
||||
|
||||
private SavingsAccountChargePaidBy getSavingsAccountChargePaidBy() {
|
||||
if (!CollectionUtils.isEmpty(this.savingsAccountChargesPaid)) {
|
||||
return this.savingsAccountChargesPaid.iterator().next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isPaymentForCurrentCharge(final SavingsAccountCharge savingsAccountCharge) {
|
||||
final SavingsAccountChargePaidBy chargePaidBy = getSavingsAccountChargePaidBy();
|
||||
return chargePaidBy != null && chargePaidBy.getSavingsAccountCharge().equals(savingsAccountCharge);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<OffsetDateTime> getCreatedDate() {
|
||||
// #audit backward compatibility keep system datetime
|
||||
return Optional.ofNullable(super.getCreatedDate()
|
||||
.orElse(createdDateToRemove == null ? null : createdDateToRemove.atZone(getSystemZoneId()).toOffsetDateTime()));
|
||||
}
|
||||
|
||||
public boolean isAmountOnHoldNotReleased() {
|
||||
return (isAmountOnHold() && getReleaseIdOfHoldAmountTransaction() == null);
|
||||
}
|
||||
|
||||
public SavingsAccountTransactionDetailsForPostingPeriod toSavingsAccountTransactionDetailsForPostingPeriod(MonetaryCurrency currency,
|
||||
boolean isAllowOverDraft) {
|
||||
return new SavingsAccountTransactionDetailsForPostingPeriod(getId(), this.dateOf, this.balanceEndDate, this.runningBalance,
|
||||
this.amount, currency, this.balanceNumberOfDays, isDeposit(), isWithdrawal(), isAllowOverDraft,
|
||||
isChargeTransactionAndNotReversed(), isDividendPayoutAndNotReversed());
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import java.util.Comparator;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
|
||||
/**
|
||||
* Sort savings account transactions by transaction date and transaction type placing
|
||||
*/
|
||||
public class SavingsAccountTransactionComparator implements Comparator<SavingsAccountTransaction> {
|
||||
|
||||
@Override
|
||||
public int compare(final SavingsAccountTransaction o1, final SavingsAccountTransaction o2) {
|
||||
int result = DateUtils.compare(o1.getTransactionDate(), o2.getTransactionDate());
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = DateUtils.compare(o1.getCreatedDateTime(), o2.getCreatedDateTime());
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
if (o1.getId() != null && o2.getId() != null) {
|
||||
return o1.getId().compareTo(o2.getId());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import java.util.Comparator;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData;
|
||||
|
||||
public class SavingsAccountTransactionDataComparator implements Comparator<SavingsAccountTransactionData> {
|
||||
|
||||
@Override
|
||||
public int compare(final SavingsAccountTransactionData o1, final SavingsAccountTransactionData o2) {
|
||||
int result = DateUtils.compare(o1.getTransactionDate(), o2.getTransactionDate());
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = DateUtils.compare(o1.getSubmittedOnDate(), o2.getSubmittedOnDate());
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
if (o1.getId() != null && o2.getId() != null) {
|
||||
return o1.getId().compareTo(o2.getId());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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 jakarta.persistence.LockModeType;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Lock;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface SavingsAccountTransactionRepository
|
||||
extends JpaRepository<SavingsAccountTransaction, Long>, JpaSpecificationExecutor<SavingsAccountTransaction> {
|
||||
|
||||
@Query("select sat from SavingsAccountTransaction sat where sat.id = :transactionId and sat.savingsAccount.id = :savingsId")
|
||||
SavingsAccountTransaction findOneByIdAndSavingsAccountId(@Param("transactionId") Long transactionId,
|
||||
@Param("savingsId") Long savingsId);
|
||||
|
||||
@Lock(LockModeType.PESSIMISTIC_WRITE)
|
||||
@Query("select st from SavingsAccountTransaction st where st.savingsAccount = :savingsAccount and st.dateOf >= :transactionDate order by st.dateOf,st.createdDate,st.id")
|
||||
List<SavingsAccountTransaction> findTransactionsAfterPivotDate(@Param("savingsAccount") SavingsAccount savingsAccount,
|
||||
@Param("transactionDate") LocalDate transactionDate);
|
||||
|
||||
@Lock(LockModeType.PESSIMISTIC_WRITE)
|
||||
@Query("select st from SavingsAccountTransaction st where st.savingsAccount = :savingsAccount and st.dateOf = :date and st.reversalTransaction <> 1 and st.reversed <> 1 order by st.id")
|
||||
List<SavingsAccountTransaction> findTransactionRunningBalanceBeforePivotDate(@Param("savingsAccount") SavingsAccount savingsAccount,
|
||||
@Param("date") LocalDate date);
|
||||
|
||||
@Lock(LockModeType.PESSIMISTIC_WRITE)
|
||||
List<SavingsAccountTransaction> findBySavingsAccount(@Param("savingsAccount") SavingsAccount savingsAccount);
|
||||
|
||||
List<SavingsAccountTransaction> findByRefNo(@Param("refNo") String refNo);
|
||||
|
||||
@Query("select sat from SavingsAccountTransaction sat where sat.savingsAccount.id = :savingsId and sat.dateOf <= :transactionDate and sat.reversed=false")
|
||||
List<SavingsAccountTransaction> findBySavingsAccountIdAndLessThanDateOfAndReversedIsFalse(@Param("savingsId") Long savingsId,
|
||||
@Param("transactionDate") LocalDate transactionDate, Pageable pageable);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user