From 628a6d778bb46b89e3b979f738221b6200ad5d0e Mon Sep 17 00:00:00 2001 From: mifoscontributer Date: Fri, 28 Jun 2013 11:38:44 +0530 Subject: [PATCH] Add Loan cycle counter for client Update the sql version --- .../V72__add_m_loan_counter_changes.sql | 19 ++++++ .../client/data/ClientAccountSummaryData.java | 7 ++- .../ClientReadPlatformServiceImpl.java | 9 ++- .../loanaccount/domain/LoanCycle.java | 60 +++++++++++++++++++ .../domain/LoanCycleRepository.java | 15 +++++ .../loanaccount/domain/LoanRepository.java | 4 ++ ...WritePlatformServiceJpaRepositoryImpl.java | 55 ++++++++++++++++- .../api/LoanProductsApiResource.java | 18 +++--- .../loanproduct/data/LoanProductData.java | 14 +++-- .../loanproduct/domain/LoanProduct.java | 16 ++++- .../LoanProductDataValidator.java | 5 +- .../LoanProductReadPlatformServiceImpl.java | 6 +- 12 files changed, 205 insertions(+), 23 deletions(-) create mode 100644 mifosng-db/migrations/core_db/V72__add_m_loan_counter_changes.sql create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanCycle.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanCycleRepository.java diff --git a/mifosng-db/migrations/core_db/V72__add_m_loan_counter_changes.sql b/mifosng-db/migrations/core_db/V72__add_m_loan_counter_changes.sql new file mode 100644 index 000000000..ffee4856e --- /dev/null +++ b/mifosng-db/migrations/core_db/V72__add_m_loan_counter_changes.sql @@ -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; \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientAccountSummaryData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientAccountSummaryData.java index 4495360df..472c6a269 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientAccountSummaryData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientAccountSummaryData.java @@ -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() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformServiceImpl.java index c7674f427..6104022ec 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformServiceImpl.java @@ -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); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanCycle.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanCycle.java new file mode 100644 index 000000000..6f22867a3 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanCycle.java @@ -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 { + + @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; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanCycleRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanCycleRepository.java new file mode 100644 index 000000000..bcfcd9f48 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanCycleRepository.java @@ -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, JpaSpecificationExecutor { + + @Query("from LoanCycle lc where lc.client.id=:clientId and lc.loanProduct.id=:loanProductId order by lc.runningCount") + List findByClientIdAndLoanProductId(@Param("clientId") Long clientId, @Param("loanProductId") Long loanProductId); + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepository.java index a72e53ee8..48987933d 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepository.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepository.java @@ -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, @Query("from Loan loan where loan.id IN :ids and loan.loanStatus IN :loanStatuses and loan.loanType IN :loanTypes") List findByIdsAndLoanStatusAndLoanType(@Param("ids") Collection ids, @Param("loanStatuses") Collection loanStatuses, @Param("loanTypes") Collection loanTypes); + + @Query("select loan.id from Loan loan where loan.actualDisbursementDate > :disbursalDate order by loan.actualDisbursementDate") + List getLoansDisbursedAfter(@Param("disbursalDate") Date disbursalDate); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index c092435d8..8b66e0d24 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -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 loansToUpdateLoanCycle = this.loanRepository.getLoansDisbursedAfter(actualDisbursementDate.toDate()); + + // get all available loan cycles. + final List 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 existingTransactionIds = new ArrayList(); final List existingReversedTransactionIds = new ArrayList(); final Map 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 existingTransactionIds = new ArrayList(); final List existingReversedTransactionIds = new ArrayList(); @@ -674,6 +707,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf this.loanEventApiJsonValidator.validateTransactionWithNoAmount(command.json()); final Loan loan = retrieveLoanBy(loanId); + removeLoanCycle(loan); final Map changes = new LinkedHashMap(); 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 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); + } + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java index fcdf05d18..c105e3300 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java @@ -60,15 +60,15 @@ import org.springframework.stereotype.Component; public class LoanProductsApiResource { private final Set LOAN_PRODUCT_DATA_PARAMETERS = new HashSet(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"; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java index d228f65d9..a97b468a8 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java @@ -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 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 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 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 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 charges, final EnumOptionData accountingType) { + final Collection 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; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java index d9d894631..6d4e69acb 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java @@ -72,6 +72,9 @@ public class LoanProduct extends AbstractPersistable { @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 productCharges, final JsonCommand command, final AprCalculator aprCalculator) { @@ -111,12 +114,13 @@ public class LoanProduct extends AbstractPersistable { 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 { final Integer defaultMinNumberOfInstallments, final Integer defaultMaxNumberOfInstallments, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance, final List 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 { if (accountingRuleType != null) { this.accountingRule = accountingRuleType.getValue(); } + this.includeInBorrowerCycle = includeInBorrowerCycle; } public MonetaryCurrency getCurrency() { @@ -257,6 +262,13 @@ public class LoanProduct extends AbstractPersistable { 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; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductDataValidator.java index b62914bb2..0107e7a14 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductDataValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductDataValidator.java @@ -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); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java index f702558f8..451e9b774 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java @@ -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); } }