Merge pull request #406 from mifoscontributer/MIFOSX-212-B

Add Loan cycle counter for client
This commit is contained in:
Vishwas Babu A J
2013-06-27 23:42:06 -07:00
12 changed files with 205 additions and 23 deletions
@@ -0,0 +1,19 @@
ALTER TABLE m_product_loan
ADD COLUMN `include_in_borrower_cycle` TINYINT(1) NOT NULL DEFAULT '0';
CREATE TABLE `m_client_loan_counter` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`client_id` BIGINT(20) NOT NULL,
`loan_product_id` BIGINT(20) NOT NULL,
`loan_id` BIGINT(20) NOT NULL,
`running_count` SMALLINT(4) NOT NULL,
PRIMARY KEY (`id`),
INDEX `FK_m_client_id_loan_counter` (`client_id`),
INDEX `FK_m_loan_product_loan_counter` (`loan_product_id`),
INDEX `FK_m_client_loan_counter` (`loan_id`),
CONSTRAINT `FK_m_client_id_loan_counter` FOREIGN KEY (`client_id`) REFERENCES `m_client` (`id`),
CONSTRAINT `FK_m_loan_product_loan_counter` FOREIGN KEY (`loan_product_id`) REFERENCES `m_product_loan` (`id`),
CONSTRAINT `FK_m_client_loan_counter` FOREIGN KEY (`loan_id`) REFERENCES `m_loan` (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
@@ -30,6 +30,8 @@ public class ClientAccountSummaryData {
@SuppressWarnings("unused")
private final EnumOptionData loanType;
private final SavingsAccountStatusEnumData savingAccountStatus;
@SuppressWarnings("unused")
private final Integer loanCycle;
public ClientAccountSummaryData(final Long id, final String externalId, final Long productId, final String loanProductName,
final Integer loanStatusId) {
@@ -42,10 +44,11 @@ public class ClientAccountSummaryData {
this.status = null;
this.loanType = null;
this.savingAccountStatus = null;
this.loanCycle = null;
}
public ClientAccountSummaryData(final Long id, final String accountNo, final String externalId, final Long productId,
final String loanProductName, final LoanStatusEnumData loanStatus, final EnumOptionData loanType) {
final String loanProductName, final LoanStatusEnumData loanStatus, final EnumOptionData loanType, final Integer loanCycle) {
this.id = id;
this.accountNo = accountNo;
this.externalId = externalId;
@@ -55,6 +58,7 @@ public class ClientAccountSummaryData {
this.status = loanStatus;
this.loanType = loanType;
this.savingAccountStatus = null;
this.loanCycle = loanCycle;
}
public ClientAccountSummaryData(final Long id, final String accountNo, final String externalId, final Long productId,
@@ -68,6 +72,7 @@ public class ClientAccountSummaryData {
this.status = null;
this.loanType = null;
this.savingAccountStatus = savingAccountStatus;
this.loanCycle = null;
}
public Integer accountStatusId() {
@@ -520,8 +520,10 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
StringBuilder accountsSummary = new StringBuilder("l.id as id, l.account_no as accountNo, l.external_id as externalId,");
accountsSummary.append("l.product_id as productId, lp.name as productName,")
.append("l.loan_status_id as statusId, l.loan_type_enum as loanType ").append("from m_loan l ")
.append("LEFT JOIN m_product_loan AS lp ON lp.id = l.product_id ");
.append("l.loan_status_id as statusId, l.loan_type_enum as loanType, ")
.append("lc.running_count as loanCycle ").append(" from m_loan l ")
.append("LEFT JOIN m_product_loan AS lp ON lp.id = l.product_id ")
.append("LEFT JOIN m_client_loan_counter lc on l.id = lc.loan_id ");
return accountsSummary.toString();
}
@@ -538,8 +540,9 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final LoanStatusEnumData loanStatus = LoanEnumerations.status(loanStatusId);
final Integer loanTypeId = JdbcSupport.getInteger(rs, "loanType");
final EnumOptionData loanType = LoanEnumerations.loanType(loanTypeId);
final Integer loanCycle = JdbcSupport.getInteger(rs, "loanCycle");
return new ClientAccountSummaryData(id, accountNo, externalId, productId, loanProductName, loanStatus, loanType);
return new ClientAccountSummaryData(id, accountNo, externalId, productId, loanProductName, loanStatus, loanType, loanCycle);
}
}
@@ -0,0 +1,60 @@
package org.mifosplatform.portfolio.loanaccount.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity
@Table(name = "m_client_loan_counter")
public class LoanCycle extends AbstractPersistable<Long> {
@ManyToOne
@JoinColumn(name = "client_id", nullable = false)
private Client client;
@ManyToOne
@JoinColumn(name = "loan_product_id", nullable = false)
private LoanProduct loanProduct;
@ManyToOne
@JoinColumn(name = "loan_id", nullable = false)
private Loan loan;
@Column(name = "running_count", nullable = false)
private Integer runningCount;
public LoanCycle() {
}
private LoanCycle(final Client client, final LoanProduct loanProduct, final Loan loan, final Integer runningCounter) {
this.client = client;
this.loanProduct = loanProduct;
this.loan = loan;
this.runningCount = runningCounter;
}
public static LoanCycle create(final Client client, final LoanProduct loanProduct, final Loan loan, final Integer runningCounter) {
return new LoanCycle(client, loanProduct, loan, runningCounter);
}
public Integer getRunningCounter() {
return this.runningCount;
}
public Loan loan() {
return this.loan;
}
public LoanCycle updateLoanCycleCounter(final Integer runningCount) {
this.runningCount = runningCount;
return this;
}
}
@@ -0,0 +1,15 @@
package org.mifosplatform.portfolio.loanaccount.domain;
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 LoanCycleRepository extends JpaRepository<LoanCycle, Long>, JpaSpecificationExecutor<LoanCycle> {
@Query("from LoanCycle lc where lc.client.id=:clientId and lc.loanProduct.id=:loanProductId order by lc.runningCount")
List<LoanCycle> findByClientIdAndLoanProductId(@Param("clientId") Long clientId, @Param("loanProductId") Long loanProductId);
}
@@ -6,6 +6,7 @@
package org.mifosplatform.portfolio.loanaccount.domain;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
@@ -23,4 +24,7 @@ public interface LoanRepository extends JpaRepository<Loan, Long>,
@Query("from Loan loan where loan.id IN :ids and loan.loanStatus IN :loanStatuses and loan.loanType IN :loanTypes")
List<Loan> findByIdsAndLoanStatusAndLoanType(@Param("ids") Collection<Long> ids, @Param("loanStatuses") Collection<Integer> loanStatuses, @Param("loanTypes") Collection<Integer> loanTypes);
@Query("select loan.id from Loan loan where loan.actualDisbursementDate > :disbursalDate order by loan.actualDisbursementDate")
List<Long> getLoansDisbursedAfter(@Param("disbursalDate") Date disbursalDate);
}
@@ -39,6 +39,7 @@ import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeUpdatedExc
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException;
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException.LOAN_CHARGE_CANNOT_BE_WAIVED_REASON;
import org.mifosplatform.portfolio.charge.exception.LoanChargeNotFoundException;
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand;
import org.mifosplatform.portfolio.collectionsheet.command.SingleDisbursalCommand;
@@ -49,6 +50,8 @@ import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateM
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
import org.mifosplatform.portfolio.loanaccount.domain.LoanChargeRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCycle;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCycleRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
@@ -64,6 +67,7 @@ import org.mifosplatform.portfolio.loanaccount.exception.LoanTransactionNotFound
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
import org.mifosplatform.portfolio.loanaccount.serialization.LoanEventApiJsonValidator;
import org.mifosplatform.portfolio.loanaccount.serialization.LoanUpdateCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.mifosplatform.portfolio.loanproduct.exception.InvalidCurrencyException;
import org.mifosplatform.portfolio.note.domain.Note;
@@ -94,6 +98,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final LoanScheduleGeneratorFactory loanScheduleFactory;
private final CalendarInstanceRepository calendarInstanceRepository;
private final PaymentDetailWritePlatformService paymentDetailWritePlatformService;
private final LoanCycleRepository loanCycleRepository;
@Autowired
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -105,7 +110,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final JournalEntryWritePlatformService journalEntryWritePlatformService, final LoanSummaryWrapper loanSummaryWrapper,
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
final LoanScheduleGeneratorFactory loanScheduleFactory, final CalendarInstanceRepository calendarInstanceRepository,
final PaymentDetailWritePlatformService paymentDetailWritePlatformService) {
final PaymentDetailWritePlatformService paymentDetailWritePlatformService, final LoanCycleRepository loanCycleRepository) {
this.context = context;
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
this.loanAssembler = loanAssembler;
@@ -122,6 +127,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.loanScheduleFactory = loanScheduleFactory;
this.calendarInstanceRepository = calendarInstanceRepository;
this.paymentDetailWritePlatformService = paymentDetailWritePlatformService;
this.loanCycleRepository = loanCycleRepository;
}
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
@@ -161,6 +167,31 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
final LocalDate firstRepaymentMeetingDate = getFirstRepaymentMeetingDate(actualDisbursementDate, loan, calendarInstance);
// create loan cycle
final LoanProduct product = loan.loanProduct();
final Client client = loan.client();
// get the loan Ids which have disbursement date greater than
// 'actualDisbursementDate'.
final List<Long> loansToUpdateLoanCycle = this.loanRepository.getLoansDisbursedAfter(actualDisbursementDate.toDate());
// get all available loan cycles.
final List<LoanCycle> loanCycles = this.loanCycleRepository.findByClientIdAndLoanProductId(client.getId(), product.getId());
Integer loanCounter = loanCycles.size() + 1;
for (final long loanCycleLoanId : loansToUpdateLoanCycle) {
for (final LoanCycle loanCycle : loanCycles) {
if (loanCycle.loan().getId() == loanCycleLoanId) {
int runningCounter = loanCycle.getRunningCounter();
if (loanCounter > runningCounter) {
loanCounter = runningCounter;
}
loanCycle.updateLoanCycleCounter(++runningCounter);
}
}
}
final LoanCycle loanCycle = LoanCycle.create(client, product, loan, loanCounter);
this.loanCycleRepository.save(loanCycle);
loan.disburse(this.loanScheduleFactory, currentUser, command, applicationCurrency, existingTransactionIds,
existingReversedTransactionIds, changes, paymentDetail, firstRepaymentMeetingDate);
@@ -273,6 +304,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
context.authenticatedUser();
final Loan loan = retrieveLoanBy(loanId);
removeLoanCycle(loan);
final List<Long> existingTransactionIds = new ArrayList<Long>();
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
final Map<String, Object> changes = loan.undoDisbursal(existingTransactionIds, existingReversedTransactionIds);
@@ -574,6 +606,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
changes.put("dateFormat", command.dateFormat());
final Loan loan = retrieveLoanBy(loanId);
removeLoanCycle(loan);
final List<Long> existingTransactionIds = new ArrayList<Long>();
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
@@ -674,6 +707,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.loanEventApiJsonValidator.validateTransactionWithNoAmount(command.json());
final Loan loan = retrieveLoanBy(loanId);
removeLoanCycle(loan);
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
@@ -1006,4 +1040,23 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
}
}
private void removeLoanCycle(final Loan loan) {
final Client client = loan.client();
final LoanProduct product = loan.loanProduct();
final List<LoanCycle> loanCycles = this.loanCycleRepository.findByClientIdAndLoanProductId(client.getId(), product.getId());
LoanCycle loanCycleToRemove = null;
for (LoanCycle loanCycle : loanCycles) {
if (loanCycle.loan().getId().equals(loan.getId())) {
loanCycleToRemove = loanCycle;
} else if (loanCycleToRemove != null) {
loanCycle = loanCycle.updateLoanCycleCounter(loanCycle.getRunningCounter() - 1);
}
}
if (loanCycleToRemove != null) {
this.loanCycleRepository.save(loanCycles);
this.loanCycleRepository.delete(loanCycleToRemove);
}
}
}
@@ -60,15 +60,15 @@ import org.springframework.stereotype.Component;
public class LoanProductsApiResource {
private final Set<String> LOAN_PRODUCT_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "name", "description", "fundId",
"fundName", "currency", "principal", "minPrincipal", "maxPrincipal", "numberOfRepayments", "minNumberOfRepayments",
"maxNumberOfRepayments", "repaymentEvery", "repaymentFrequencyType", "graceOnPrincipalPayment", "graceOnInterestPayment",
"graceOnInterestCharged", "interestRatePerPeriod", "minInterestRatePerPeriod", "maxInterestRatePerPeriod",
"interestRateFrequencyType", "annualInterestRate", "amortizationType", "interestType", "interestCalculationPeriodType",
"inArrearsTolerance", "transactionProcessingStrategyId", "transactionProcessingStrategyName", "charges", "accountingRule",
"accountingMappings", "paymentChannelToFundSourceMappings", "fundOptions", "paymentTypeOptions", "currencyOptions",
"repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "amortizationTypeOptions", "interestTypeOptions",
"interestCalculationPeriodTypeOptions", "transactionProcessingStrategyOptions", "chargeOptions", "accountingOptions",
"accountingRuleOptions", "accountingMappingOptions"));
"fundName", "includeInBorrowerCycle", "currency", "principal", "minPrincipal", "maxPrincipal", "numberOfRepayments",
"minNumberOfRepayments", "maxNumberOfRepayments", "repaymentEvery", "repaymentFrequencyType", "graceOnPrincipalPayment",
"graceOnInterestPayment", "graceOnInterestCharged", "interestRatePerPeriod", "minInterestRatePerPeriod",
"maxInterestRatePerPeriod", "interestRateFrequencyType", "annualInterestRate", "amortizationType", "interestType",
"interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "transactionProcessingStrategyName",
"charges", "accountingRule", "accountingMappings", "paymentChannelToFundSourceMappings", "fundOptions", "paymentTypeOptions",
"currencyOptions", "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "amortizationTypeOptions",
"interestTypeOptions", "interestCalculationPeriodTypeOptions", "transactionProcessingStrategyOptions", "chargeOptions",
"accountingOptions", "accountingRuleOptions", "accountingMappingOptions"));
private final String resourceNameForPermissions = "LOANPRODUCT";
@@ -37,6 +37,7 @@ public class LoanProductData {
private final String description;
private final Long fundId;
private final String fundName;
private final boolean includeInBorrowerCycle;
// terms
private final CurrencyData currency;
@@ -127,13 +128,14 @@ public class LoanProductData {
final Integer graceOnInterestCharged = null;
final Collection<ChargeData> charges = null;
final EnumOptionData accountingType = null;
final boolean includeInBorrowerCycle = false;
return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments,
minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod,
maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType,
interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId,
transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges,
accountingType);
accountingType, includeInBorrowerCycle);
}
public static LoanProductData lookupWithCurrency(final Long id, final String name, final CurrencyData currency) {
@@ -165,13 +167,14 @@ public class LoanProductData {
final Collection<ChargeData> charges = null;
final EnumOptionData accountingType = null;
final boolean includeInBorrowerCycle = false;
return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments,
minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod,
maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType,
interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId,
transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges,
accountingType);
accountingType, includeInBorrowerCycle);
}
public static LoanProductData sensibleDefaultsForNewLoanProductCreation() {
@@ -209,13 +212,14 @@ public class LoanProductData {
final Collection<ChargeData> charges = null;
final EnumOptionData accountingType = AccountingEnumerations.accountingRuleType(AccountingRuleType.NONE);
final boolean includeInBorrowerCycle = false;
return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments,
minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod,
maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType,
interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId,
transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges,
accountingType);
accountingType, includeInBorrowerCycle);
}
public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings,
@@ -238,7 +242,7 @@ public class LoanProductData {
final EnumOptionData interestCalculationPeriodType, final Long fundId, final String fundName,
final Long transactionProcessingStrategyId, final String transactionProcessingStrategyName,
final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged,
final Collection<ChargeData> charges, final EnumOptionData accountingType) {
final Collection<ChargeData> charges, final EnumOptionData accountingType, final boolean includeInBorrowerCycle) {
this.id = id;
this.name = name;
this.description = description;
@@ -269,6 +273,7 @@ public class LoanProductData {
this.transactionProcessingStrategyName = transactionProcessingStrategyName;
this.charges = charges;
this.accountingRule = accountingType;
this.includeInBorrowerCycle = includeInBorrowerCycle;
this.chargeOptions = null;
this.penaltyOptions = null;
@@ -349,6 +354,7 @@ public class LoanProductData {
this.graceOnPrincipalPayment = productData.graceOnPrincipalPayment;
this.graceOnInterestPayment = productData.graceOnInterestPayment;
this.graceOnInterestCharged = productData.graceOnInterestCharged;
this.includeInBorrowerCycle = productData.includeInBorrowerCycle;
this.amortizationTypeOptions = amortizationTypeOptions;
this.interestTypeOptions = interestTypeOptions;
@@ -72,6 +72,9 @@ public class LoanProduct extends AbstractPersistable<Long> {
@Column(name = "accounting_type", nullable = false)
private Integer accountingRule;
@Column(name = "include_in_borrower_cycle")
private boolean includeInBorrowerCycle;
public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy,
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator) {
@@ -111,12 +114,13 @@ public class LoanProduct extends AbstractPersistable<Long> {
final Integer graceOnInterestCharged = command.integerValueOfParameterNamed("graceOnInterestCharged");
final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(command.integerValueOfParameterNamed("accountingRule"));
final boolean includeInBorrowerCycle = command.booleanPrimitiveValueOfParameterNamed("includeInBorrowerCycle");
return new LoanProduct(fund, loanTransactionProcessingStrategy, name, description, currency, principal, minPrincipal, maxPrincipal,
interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType, annualInterestRate,
interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentFrequencyType, numberOfRepayments,
minNumberOfRepayments, maxNumberOfRepayments, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
amortizationMethod, inArrearsTolerance, productCharges, accountingRuleType);
amortizationMethod, inArrearsTolerance, productCharges, accountingRuleType, includeInBorrowerCycle);
}
protected LoanProduct() {
@@ -135,7 +139,7 @@ public class LoanProduct extends AbstractPersistable<Long> {
final Integer defaultMinNumberOfInstallments, final Integer defaultMaxNumberOfInstallments,
final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged,
final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance, final List<Charge> charges,
final AccountingRuleType accountingRuleType) {
final AccountingRuleType accountingRuleType, final boolean includeInBorrowerCycle) {
this.fund = fund;
this.transactionProcessingStrategy = transactionProcessingStrategy;
this.name = name.trim();
@@ -163,6 +167,7 @@ public class LoanProduct extends AbstractPersistable<Long> {
if (accountingRuleType != null) {
this.accountingRule = accountingRuleType.getValue();
}
this.includeInBorrowerCycle = includeInBorrowerCycle;
}
public MonetaryCurrency getCurrency() {
@@ -257,6 +262,13 @@ public class LoanProduct extends AbstractPersistable<Long> {
actualChanges.put(chargesParamName, command.jsonFragment(chargesParamName));
}
}
final String includeInBorrowerCycleParamName = "includeInBorrowerCycle";
if (command.isChangeInBooleanParameterNamed(includeInBorrowerCycleParamName, this.includeInBorrowerCycle)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(includeInBorrowerCycleParamName);
actualChanges.put(includeInBorrowerCycleParamName, newValue);
this.includeInBorrowerCycle = newValue;
}
return actualChanges;
}
@@ -43,7 +43,7 @@ public final class LoanProductDataValidator {
"minNumberOfRepayments", "maxNumberOfRepayments", "repaymentFrequencyType", "interestRatePerPeriod",
"minInterestRatePerPeriod", "maxInterestRatePerPeriod", "interestRateFrequencyType", "amortizationType", "interestType",
"interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "graceOnPrincipalPayment",
"graceOnInterestPayment", "graceOnInterestCharged", "charges", "accountingRule",
"graceOnInterestPayment", "graceOnInterestCharged", "charges", "accountingRule","includeInBorrowerCycle",
LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(),
@@ -81,6 +81,9 @@ public final class LoanProductDataValidator {
final Long fundId = fromApiJsonHelper.extractLongNamed("fundId", element);
baseDataValidator.reset().parameter("fundId").value(fundId).ignoreIfNull().integerGreaterThanZero();
}
final Boolean includeInBorrowerCycle = fromApiJsonHelper.extractBooleanNamed("includeInBorrowerCycle", element);
baseDataValidator.reset().parameter("includeInBorrowerCycle").value(includeInBorrowerCycle).notNull();
// terms
final String currencyCode = fromApiJsonHelper.extractStringNamed("currencyCode", element);
@@ -103,7 +103,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
+ "lp.repay_every as repaidEvery, lp.repayment_period_frequency_enum as repaymentPeriodFrequency, lp.number_of_repayments as numberOfRepayments, lp.min_number_of_repayments as minNumberOfRepayments, lp.max_number_of_repayments as maxNumberOfRepayments, "
+ "lp.grace_on_principal_periods as graceOnPrincipalPayment, lp.grace_on_interest_periods as graceOnInterestPayment, lp.grace_interest_free_periods as graceOnInterestCharged,"
+ "lp.amortization_method_enum as amortizationMethod, lp.arrearstolerance_amount as tolerance, "
+ "lp.accounting_type as accountingType, "
+ "lp.accounting_type as accountingType, lp.include_in_borrower_cycle as includeInBorrowerCycle, "
+ "curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol "
+ " from m_product_loan lp "
+ " left join m_fund f on f.id = lp.fund_id"
@@ -168,13 +168,15 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
final int interestCalculationPeriodTypeId = JdbcSupport.getInteger(rs, "interestCalculationInPeriodMethod");
final EnumOptionData interestCalculationPeriodType = LoanEnumerations
.interestCalculationPeriodType(interestCalculationPeriodTypeId);
final boolean includeInBorrowerCycle = rs.getBoolean("includeInBorrowerCycle");
return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType,
interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, fundId, fundName,
transactionStrategyId, transactionStrategyName, graceOnPrincipalPayment, graceOnInterestPayment,
graceOnInterestCharged, this.charges, accountingRuleType);
graceOnInterestCharged, this.charges, accountingRuleType, includeInBorrowerCycle);
}
}