/** * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mifosplatform.integrationtests.common.loans; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.mifosplatform.integrationtests.common.Utils; import org.mifosplatform.integrationtests.common.accounting.Account; import com.google.gson.Gson; import com.google.gson.JsonObject; public class LoanProductTestBuilder { private static final String LOCALE = "en_GB"; private static final String USD = "USD"; private static final String DAYS = "0"; private static final String WEEK = "1"; private static final String MONTHS = "2"; private static final String YEARS = "3"; private static final String CALCULATION_PERIOD_SAME_AS_REPAYMENT_PERIOD = "1"; private static final String EQUAL_PRINCIPAL_PAYMENTS = "0"; private static final String EQUAL_INSTALLMENTS = "1"; private static final String DECLINING_BALANCE = "0"; private static final String FLAT_BALANCE = "1"; public static final String MIFOS_STANDARD_STRATEGY = "1"; // private static final String HEAVENS_FAMILY_STRATEGY ="2"; // private static final String CREO_CORE_STRATEGY ="3"; public static final String RBI_INDIA_STRATEGY = "4"; public static final String RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD = "1"; public static final String RECALCULATION_FREQUENCY_TYPE_DAILY = "2"; public static final String RECALCULATION_FREQUENCY_TYPE_WEEKLY = "3"; public static final String RECALCULATION_FREQUENCY_TYPE_MONTHLY = "4"; public static final String RECALCULATION_STRATEGY_RESCHEDULE_NEXT_REPAYMENTS = "1"; public static final String RECALCULATION_STRATEGY_REDUCE_NUMBER_OF_INSTALLMENTS = "2"; public static final String RECALCULATION_STRATEGY_REDUCE_EMI_AMOUN = "3"; public static final String RECALCULATION_COMPOUNDING_METHOD_NONE = "0"; public static final String RECALCULATION_COMPOUNDING_METHOD_INTEREST = "1"; public static final String RECALCULATION_COMPOUNDING_METHOD_FEE = "2"; public static final String RECALCULATION_COMPOUNDING_METHOD_INTEREST_AND_FEE = "3"; private static final String NONE = "1"; private static final String CASH_BASED = "2"; private static final String ACCRUAL_PERIODIC = "3"; private static final String ACCRUAL_UPFRONT = "4"; public static final String INTEREST_APPLICABLE_STRATEGY_REST_DATE = "2"; public static final String INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE = "1"; private String digitsAfterDecimal = "2"; private String inMultiplesOf = "0"; private String nameOfLoanProduct = Utils.randomNameGenerator("LOAN_PRODUCT_", 6); private final String shortName = Utils.randomNameGenerator("", 4); private String principal = "10000.00"; private String numberOfRepayments = "5"; private String repaymentFrequency = MONTHS; private String repaymentPeriod = "1"; private String interestRatePerPeriod = "2"; private String interestRateFrequencyType = MONTHS; private String interestType = FLAT_BALANCE; private String overdueDaysForNPA = "5"; private String interestCalculationPeriodType = CALCULATION_PERIOD_SAME_AS_REPAYMENT_PERIOD; private String inArrearsTolerance = "0"; private String transactionProcessingStrategy = MIFOS_STANDARD_STRATEGY; private String accountingRule = NONE; private final String currencyCode = USD; private String amortizationType = EQUAL_INSTALLMENTS; private String minPrincipal = "1000.00"; private String maxPrincipal = "10000000.00"; private Account[] accountList = null; private Boolean multiDisburseLoan = false; private final String outstandingLoanBalance = "35000"; private final String maxTrancheCount = "3"; private Boolean isInterestRecalculationEnabled = false; private String daysInYearType = "1"; private String daysInMonthType = "1"; private String interestRecalculationCompoundingMethod = "0"; private String preCloseInterestCalculationStrategy = INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE; private String rescheduleStrategyMethod = "1"; private String recalculationRestFrequencyType = "1"; private String recalculationRestFrequencyInterval = "0"; private String recalculationRestFrequencyDate = null; private String recalculationCompoundingFrequencyType = null; private String recalculationCompoundingFrequencyInterval = null; private String recalculationCompoundingFrequencyDate = null; private String minimumDaysBetweenDisbursalAndFirstRepayment = null; private Boolean holdGuaranteeFunds = null; private String mandatoryGuarantee = null; private String minimumGuaranteeFromOwnFunds = null; private String minimumGuaranteeFromGuarantor = null; private String isArrearsBasedOnOriginalSchedule = null; private String graceOnPrincipalPayment = "1"; private String graceOnInterestPayment = "1"; private JsonObject allowAttributeOverrides = null; private Boolean allowPartialPeriodInterestCalcualtion = false; private Boolean allowVariableInstallments = Boolean.FALSE; private Integer minimumGap; private Integer maximumGap; public String build(final String chargeId) { final HashMap<String, Object> map = new HashMap<>(); if (chargeId != null) { List<HashMap<String, String>> charges = new ArrayList<>(); HashMap<String, String> chargeMap = new HashMap<>(); chargeMap.put("id", chargeId); charges.add(chargeMap); map.put("charges", charges); } map.put("name", this.nameOfLoanProduct); map.put("shortName", this.shortName); map.put("currencyCode", this.currencyCode); map.put("locale", LOCALE); map.put("dateFormat", "dd MMMM yyyy"); map.put("digitsAfterDecimal", digitsAfterDecimal); map.put("inMultiplesOf", inMultiplesOf); map.put("principal", this.principal); map.put("numberOfRepayments", this.numberOfRepayments); map.put("repaymentEvery", this.repaymentPeriod); map.put("repaymentFrequencyType", this.repaymentFrequency); map.put("interestRatePerPeriod", this.interestRatePerPeriod); map.put("interestRateFrequencyType", this.interestRateFrequencyType); map.put("amortizationType", this.amortizationType); map.put("interestType", this.interestType); map.put("interestCalculationPeriodType", this.interestCalculationPeriodType); map.put("inArrearsTolerance", this.inArrearsTolerance); map.put("transactionProcessingStrategyId", this.transactionProcessingStrategy); map.put("accountingRule", this.accountingRule); map.put("minPrincipal", this.minPrincipal); map.put("maxPrincipal", this.maxPrincipal); map.put("overdueDaysForNPA", this.overdueDaysForNPA); if (this.minimumDaysBetweenDisbursalAndFirstRepayment != null) { map.put("minimumDaysBetweenDisbursalAndFirstRepayment", this.minimumDaysBetweenDisbursalAndFirstRepayment); } if (multiDisburseLoan) { map.put("multiDisburseLoan", this.multiDisburseLoan); map.put("maxTrancheCount", this.maxTrancheCount); map.put("outstandingLoanBalance", this.outstandingLoanBalance); } if (this.accountingRule.equals(ACCRUAL_UPFRONT) || this.accountingRule.equals(ACCRUAL_PERIODIC)) { map.putAll(getAccountMappingForAccrualBased()); } else if (this.accountingRule.equals(CASH_BASED)) { map.putAll(getAccountMappingForCashBased()); } map.put("daysInMonthType", this.daysInMonthType); map.put("daysInYearType", this.daysInYearType); map.put("isInterestRecalculationEnabled", this.isInterestRecalculationEnabled); if (this.isInterestRecalculationEnabled) { map.put("interestRecalculationCompoundingMethod", this.interestRecalculationCompoundingMethod); map.put("rescheduleStrategyMethod", this.rescheduleStrategyMethod); map.put("recalculationRestFrequencyType", recalculationRestFrequencyType); map.put("recalculationRestFrequencyInterval", recalculationRestFrequencyInterval); map.put("recalculationRestFrequencyDate", recalculationRestFrequencyDate); if (!RECALCULATION_COMPOUNDING_METHOD_NONE.equals(this.interestRecalculationCompoundingMethod)) { map.put("recalculationCompoundingFrequencyType", recalculationCompoundingFrequencyType); map.put("recalculationCompoundingFrequencyInterval", recalculationCompoundingFrequencyInterval); map.put("recalculationCompoundingFrequencyDate", recalculationCompoundingFrequencyDate); } map.put("preClosureInterestCalculationStrategy", preCloseInterestCalculationStrategy); if (isArrearsBasedOnOriginalSchedule != null) { map.put("isArrearsBasedOnOriginalSchedule", isArrearsBasedOnOriginalSchedule); } } if (holdGuaranteeFunds != null) { map.put("holdGuaranteeFunds", this.holdGuaranteeFunds); if (this.holdGuaranteeFunds) { map.put("mandatoryGuarantee", this.mandatoryGuarantee); map.put("minimumGuaranteeFromGuarantor", this.minimumGuaranteeFromGuarantor); map.put("minimumGuaranteeFromOwnFunds", this.minimumGuaranteeFromOwnFunds); } } map.put("graceOnPrincipalPayment", graceOnPrincipalPayment); map.put("graceOnInterestPayment", graceOnInterestPayment); if (allowAttributeOverrides != null) { map.put("allowAttributeOverrides", this.allowAttributeOverrides); } map.put("allowPartialPeriodInterestCalcualtion", this.allowPartialPeriodInterestCalcualtion); map.put("allowVariableInstallments", allowVariableInstallments) ; if(allowVariableInstallments) { map.put("minimumGap", minimumGap) ; map.put("maximumGap", maximumGap) ; } return new Gson().toJson(map); } public LoanProductTestBuilder withMinPrincipal(final String minPrincipal) { this.minPrincipal = minPrincipal; return this; } public LoanProductTestBuilder withMaxPrincipal(final String maxPrincipal) { this.maxPrincipal = maxPrincipal; return this; } public LoanProductTestBuilder withLoanName(final String loanName) { this.nameOfLoanProduct = loanName; return this; } public LoanProductTestBuilder withPrincipal(final String principal) { this.principal = principal; return this; } public LoanProductTestBuilder withNumberOfRepayments(final String numberOfRepayment) { this.numberOfRepayments = numberOfRepayment; return this; } public LoanProductTestBuilder withRepaymentTypeAsMonth() { this.repaymentFrequency = MONTHS; return this; } public LoanProductTestBuilder withRepaymentTypeAsWeek() { this.repaymentFrequency = WEEK; return this; } public LoanProductTestBuilder withRepaymentTypeAsDays() { this.repaymentFrequency = DAYS; return this; } public LoanProductTestBuilder withRepaymentAfterEvery(final String repaymentAfterEvery) { this.repaymentPeriod = repaymentAfterEvery; return this; } public LoanProductTestBuilder withInterestRateFrequencyTypeAsMonths() { this.interestRateFrequencyType = MONTHS; return this; } public LoanProductTestBuilder withInterestRateFrequencyTypeAsYear() { this.interestRateFrequencyType = YEARS; return this; } public LoanProductTestBuilder withinterestRatePerPeriod(final String interestRatePerPeriod) { this.interestRatePerPeriod = interestRatePerPeriod; return this; } public LoanProductTestBuilder withAmortizationTypeAsEqualPrincipalPayment() { this.amortizationType = EQUAL_PRINCIPAL_PAYMENTS; return this; } public LoanProductTestBuilder withAmortizationTypeAsEqualInstallments() { this.amortizationType = EQUAL_INSTALLMENTS; return this; } public LoanProductTestBuilder withInterestTypeAsFlat() { this.interestType = FLAT_BALANCE; return this; } public LoanProductTestBuilder withInterestTypeAsDecliningBalance() { this.interestType = DECLINING_BALANCE; return this; } public LoanProductTestBuilder withOverdueDaysForNPA(String days) { this.overdueDaysForNPA = days; return this; } public LoanProductTestBuilder withInterestCalculationPeriodTypeAsDays() { this.interestCalculationPeriodType = DAYS; return this; } public LoanProductTestBuilder withInterestCalculationPeriodTypeAsRepaymentPeriod(final Boolean allowPartialPeriodInterestCalcualtion) { this.interestCalculationPeriodType = CALCULATION_PERIOD_SAME_AS_REPAYMENT_PERIOD; this.allowPartialPeriodInterestCalcualtion = allowPartialPeriodInterestCalcualtion; return this; } public LoanProductTestBuilder withInArrearsTolerance(final String amountCanBeWaved) { this.inArrearsTolerance = amountCanBeWaved; return this; } public LoanProductTestBuilder withAccountingRuleAsNone() { this.accountingRule = NONE; return this; } public LoanProductTestBuilder withAccountingRuleAsCashBased(final Account[] account_list) { this.accountingRule = CASH_BASED; this.accountList = account_list; return this; } public LoanProductTestBuilder withAccountingRuleUpfrontAccrual(final Account[] account_list) { this.accountingRule = ACCRUAL_UPFRONT; this.accountList = account_list; return this; } public LoanProductTestBuilder withAccountingRulePeriodicAccrual(final Account[] account_list) { this.accountingRule = ACCRUAL_PERIODIC; this.accountList = account_list; return this; } public LoanProductTestBuilder withTranches(boolean multiDisburseLoan) { this.multiDisburseLoan = multiDisburseLoan; return this; } private Map<String, String> getAccountMappingForCashBased() { final Map<String, String> map = new HashMap<>(); for (int i = 0; i < this.accountList.length; i++) { if (this.accountList[i].getAccountType().equals(Account.AccountType.ASSET)) { final String ID = this.accountList[i].getAccountID().toString(); map.put("fundSourceAccountId", ID); map.put("loanPortfolioAccountId", ID); map.put("transfersInSuspenseAccountId", ID); } if (this.accountList[i].getAccountType().equals(Account.AccountType.INCOME)) { final String ID = this.accountList[i].getAccountID().toString(); map.put("interestOnLoanAccountId", ID); map.put("incomeFromFeeAccountId", ID); map.put("incomeFromPenaltyAccountId", ID); map.put("incomeFromRecoveryAccountId", ID); } if (this.accountList[i].getAccountType().equals(Account.AccountType.EXPENSE)) { final String ID = this.accountList[i].getAccountID().toString(); map.put("writeOffAccountId", ID); } if (this.accountList[i].getAccountType().equals(Account.AccountType.LIABILITY)) { final String ID = this.accountList[i].getAccountID().toString(); map.put("overpaymentLiabilityAccountId", ID); } } return map; } private Map<String, String> getAccountMappingForAccrualBased() { final Map<String, String> map = new HashMap<>(); for (int i = 0; i < this.accountList.length; i++) { if (this.accountList[i].getAccountType().equals(Account.AccountType.ASSET)) { final String ID = this.accountList[i].getAccountID().toString(); map.put("fundSourceAccountId", ID); map.put("loanPortfolioAccountId", ID); map.put("transfersInSuspenseAccountId", ID); map.put("receivableInterestAccountId", ID); map.put("receivableFeeAccountId", ID); map.put("receivablePenaltyAccountId", ID); } if (this.accountList[i].getAccountType().equals(Account.AccountType.INCOME)) { final String ID = this.accountList[i].getAccountID().toString(); map.put("interestOnLoanAccountId", ID); map.put("incomeFromFeeAccountId", ID); map.put("incomeFromPenaltyAccountId", ID); map.put("incomeFromRecoveryAccountId", ID); } if (this.accountList[i].getAccountType().equals(Account.AccountType.EXPENSE)) { final String ID = this.accountList[i].getAccountID().toString(); map.put("writeOffAccountId", ID); } if (this.accountList[i].getAccountType().equals(Account.AccountType.LIABILITY)) { final String ID = this.accountList[i].getAccountID().toString(); map.put("overpaymentLiabilityAccountId", ID); } } return map; } public LoanProductTestBuilder withAccounting(final String accountingRule, final Account[] account_list) { this.accountingRule = accountingRule; this.accountList = account_list; return this; } public LoanProductTestBuilder currencyDetails(final String digitsAfterDecimal, final String inMultiplesOf) { this.digitsAfterDecimal = digitsAfterDecimal; this.inMultiplesOf = inMultiplesOf; return this; } public LoanProductTestBuilder withRepaymentStrategy(final String transactionProcessingStrategy) { this.transactionProcessingStrategy = transactionProcessingStrategy; return this; } public LoanProductTestBuilder withDaysInMonth(final String daysInMonthType) { this.daysInMonthType = daysInMonthType; return this; } public LoanProductTestBuilder withDaysInYear(final String daysInYearType) { this.daysInYearType = daysInYearType; return this; } public LoanProductTestBuilder withInterestRecalculationDetails(final String interestRecalculationCompoundingMethod, final String rescheduleStrategyMethod, String preCloseInterestCalculationStrategy) { this.isInterestRecalculationEnabled = true; this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod; this.rescheduleStrategyMethod = rescheduleStrategyMethod; this.preCloseInterestCalculationStrategy = preCloseInterestCalculationStrategy; return this; } public LoanProductTestBuilder withInterestRecalculationRestFrequencyDetails(final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval, final String recalculationRestFrequencyDate) { this.isInterestRecalculationEnabled = true; this.recalculationRestFrequencyType = recalculationRestFrequencyType; this.recalculationRestFrequencyInterval = recalculationRestFrequencyInterval; this.recalculationRestFrequencyDate = recalculationRestFrequencyDate; return this; } public LoanProductTestBuilder withInterestRecalculationCompoundingFrequencyDetails(final String recalculationCompoundingFrequencyType, final String recalculationCompoundingFrequencyInterval, final String recalculationCompoundingFrequencyDate) { this.isInterestRecalculationEnabled = true; this.recalculationCompoundingFrequencyType = recalculationCompoundingFrequencyType; this.recalculationCompoundingFrequencyInterval = recalculationCompoundingFrequencyInterval; this.recalculationCompoundingFrequencyDate = recalculationCompoundingFrequencyDate; return this; } public LoanProductTestBuilder withMinimumDaysBetweenDisbursalAndFirstRepayment(final String minimumDaysBetweenDisbursalAndFirstRepayment) { this.minimumDaysBetweenDisbursalAndFirstRepayment = minimumDaysBetweenDisbursalAndFirstRepayment; return this; } public LoanProductTestBuilder withArrearsConfiguration() { this.isArrearsBasedOnOriginalSchedule = "true"; return this; } public LoanProductTestBuilder withOnHoldFundDetails(final String mandatoryGuarantee, final String minimumGuaranteeFromGuarantor, final String minimumGuaranteeFromOwnFunds) { this.holdGuaranteeFunds = true; this.mandatoryGuarantee = mandatoryGuarantee; this.minimumGuaranteeFromGuarantor = minimumGuaranteeFromGuarantor; this.minimumGuaranteeFromOwnFunds = minimumGuaranteeFromOwnFunds; return this; } public LoanProductTestBuilder withMoratorium(String principal, String interest) { this.graceOnPrincipalPayment = principal; this.graceOnInterestPayment = interest; return this; } public LoanProductTestBuilder withLoanProductConfiguration(JsonObject loanProductConfigurableAttributes) { this.allowAttributeOverrides = loanProductConfigurableAttributes; return this; } public LoanProductTestBuilder withVariableInstallmentsConfig(Boolean allowVariableInstallments, Integer minimumGap, Integer maximumGap) { this.allowVariableInstallments = allowVariableInstallments ; this.minimumGap = minimumGap; this.maximumGap = maximumGap; return this ; } }