From 97bf8e2f93a38871acfbae4ac47ddb2701d246fc Mon Sep 17 00:00:00 2001 From: Keith Woodlock Date: Mon, 30 Jul 2012 12:44:06 +0100 Subject: [PATCH] add relationship between loan product and the loan transaction processing strategy. its optional by default for loan product and loans. If no value selected it will default to the the 'Mifos style' repayment strategy which is pay off interest, then principal in all cases. --- .../0001a-mifos-platform-base-ddl-schema.sql | 16 +++++++ ...ction-strategy-table-and-relationships.sql | 21 ++++++++ .../platform/api/LoanProductsApiResource.java | 12 +++-- .../api/commands/LoanProductCommand.java | 12 ++++- .../platform/api/data/LoanProductData.java | 37 ++++++++++++-- .../TransactionProcessingStrategyData.java | 27 +++++++++++ .../ApiDataConversionServiceImpl.java | 10 ++-- ...onProcessingStrategyNotFoundException.java | 11 +++++ .../platform/loan/domain/LoanProduct.java | 22 ++++++--- .../LoanTransactionProcessingStrategy.java | 35 ++++++++++++++ ...ansactionProcessingStrategyRepository.java | 9 ++++ .../LoanDropdownReadPlatformService.java | 4 ++ .../LoanDropdownReadPlatformServiceImpl.java | 29 ++++++++++- .../LoanProductReadPlatformServiceImpl.java | 48 ++++++++----------- ...WritePlatformServiceJpaRepositoryImpl.java | 25 ++++++++-- 15 files changed, 268 insertions(+), 50 deletions(-) create mode 100644 mifosng-db/patches-post-multi-tenant/patch-0007-add-loan-transaction-strategy-table-and-relationships.sql create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/api/data/TransactionProcessingStrategyData.java create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/exceptions/LoanTransactionProcessingStrategyNotFoundException.java create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanTransactionProcessingStrategy.java create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanTransactionProcessingStrategyRepository.java diff --git a/mifosng-db/0001a-mifos-platform-base-ddl-schema.sql b/mifosng-db/0001a-mifos-platform-base-ddl-schema.sql index d490b4b0b..a2e5075db 100644 --- a/mifosng-db/0001a-mifos-platform-base-ddl-schema.sql +++ b/mifosng-db/0001a-mifos-platform-base-ddl-schema.sql @@ -63,6 +63,18 @@ CREATE TABLE `ref_loan_status` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE `ref_loan_transaction_processing_strategy` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `code` varchar(100) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `createdby_id` bigint(20) DEFAULT NULL, + `created_date` datetime DEFAULT NULL, + `lastmodifiedby_id` bigint(20) DEFAULT NULL, + `lastmodified_date` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ltp_strategy_code` (`code`) +) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8; + -- DDL for organisation wide related concepts CREATE TABLE `org_fund` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, @@ -216,6 +228,7 @@ CREATE TABLE `portfolio_client` ( CONSTRAINT `FKCE00CAB3E0DD567A` FOREIGN KEY (`office_id`) REFERENCES `org_office` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; + CREATE TABLE `portfolio_product_loan` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `currency_code` varchar(3) NOT NULL, @@ -225,6 +238,7 @@ CREATE TABLE `portfolio_product_loan` ( `name` varchar(100) NOT NULL, `description` varchar(500) DEFAULT NULL, `fund_id` bigint(20) DEFAULT NULL, + `loan_transaction_strategy_id` bigint(20) DEFAULT NULL, `nominal_interest_rate_per_period` decimal(19,6) NOT NULL, `interest_period_frequency_enum` smallint(5) NOT NULL, `annual_nominal_interest_rate` decimal(19,6) NOT NULL, @@ -244,6 +258,8 @@ CREATE TABLE `portfolio_product_loan` ( KEY `FKAUD0000000000003` (`createdby_id`), KEY `FKAUD0000000000004` (`lastmodifiedby_id`), KEY `FKA6A8A7D77240145` (`fund_id`), + KEY `FK_ltp_strategy` (`loan_transaction_strategy_id`), + CONSTRAINT `FK_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`), CONSTRAINT `FKA6A8A7D77240145` FOREIGN KEY (`fund_id`) REFERENCES `org_fund` (`id`), CONSTRAINT `FKAUD0000000000003` FOREIGN KEY (`createdby_id`) REFERENCES `admin_appuser` (`id`), CONSTRAINT `FKAUD0000000000004` FOREIGN KEY (`lastmodifiedby_id`) REFERENCES `admin_appuser` (`id`) diff --git a/mifosng-db/patches-post-multi-tenant/patch-0007-add-loan-transaction-strategy-table-and-relationships.sql b/mifosng-db/patches-post-multi-tenant/patch-0007-add-loan-transaction-strategy-table-and-relationships.sql new file mode 100644 index 000000000..e2b46a677 --- /dev/null +++ b/mifosng-db/patches-post-multi-tenant/patch-0007-add-loan-transaction-strategy-table-and-relationships.sql @@ -0,0 +1,21 @@ +-- add loan transactions processing table + +CREATE TABLE `ref_loan_transaction_processing_strategy` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `code` varchar(100) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `createdby_id` bigint(20) DEFAULT NULL, + `created_date` datetime DEFAULT NULL, + `lastmodifiedby_id` bigint(20) DEFAULT NULL, + `lastmodified_date` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ltp_strategy_code` (`code`) +) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8; + + +ALTER TABLE `portfolio_product_loan` +ADD COLUMN `loan_transaction_strategy_id` bigint(20) DEFAULT NULL, +ADD KEY `FK_ltp_strategy` (`loan_transaction_strategy_id`), +ADD CONSTRAINT `FK_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`); + +-- update ref table with out-of-the-box strategies \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/LoanProductsApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/LoanProductsApiResource.java index bcffb8131..50875f62b 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/LoanProductsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/LoanProductsApiResource.java @@ -88,12 +88,14 @@ public class LoanProductsApiResource { @Produces({MediaType.APPLICATION_JSON}) public String retrieveNewLoanProductDetails(@Context final UriInfo uriInfo) { + // TODO - KW - every addition of a parameter here requires same additon in supported params used in 'apiDataConversionService' method. Set typicalResponseParameters = new HashSet( - Arrays.asList("id", "name", "description", "fundId", "fundName", "principal", "inArrearsTolerance", "numberOfRepayments", + Arrays.asList("id", "name", "description", "fundId", "fundName", "transactionProcessingStrategyId", "transactionProcessingStrategyName", + "principal", "inArrearsTolerance", "numberOfRepayments", "repaymentEvery", "interestRatePerPeriod", "annualInterestRate", "repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "createdOn", "lastModifedOn","currencyOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", - "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions") + "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "transactionProcessingStrategyOptions") ); Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); @@ -114,7 +116,9 @@ public class LoanProductsApiResource { public String retrieveLoanProductDetails(@PathParam("productId") final Long productId, @Context final UriInfo uriInfo) { Set typicalResponseParameters = new HashSet( - Arrays.asList("id", "name", "description", "fundId", "fundName", "principal", "inArrearsTolerance", "numberOfRepayments", + Arrays.asList("id", "name", "description", "fundId", "fundName", + "transactionProcessingStrategyId", "transactionProcessingStrategyName", + "principal", "inArrearsTolerance", "numberOfRepayments", "repaymentEvery", "interestRatePerPeriod", "annualInterestRate", "repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "createdOn", "lastModifedOn") @@ -130,7 +134,7 @@ public class LoanProductsApiResource { LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId); if (template) { responseParameters.addAll(Arrays.asList("currencyOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", - "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions")); + "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "transactionProcessingStrategyOptions")); } return this.apiDataConversionService.convertLoanProductDataToJson(prettyPrint, responseParameters, loanProduct); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/LoanProductCommand.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/LoanProductCommand.java index 68fb96348..467b15a16 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/LoanProductCommand.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/LoanProductCommand.java @@ -13,6 +13,7 @@ public class LoanProductCommand { private final String description; private final Long fundId; + private final Long transactionProcessingStrategyId; private final String currencyCode; private final Integer digitsAfterDecimal; @@ -33,7 +34,7 @@ public class LoanProductCommand { private final Set modifiedParameters; public LoanProductCommand(final Set modifiedParameters, final Long id, final String name, final String description, - final Long fundId, + final Long fundId, final Long transactionProcessingStrategyId, final String currencyCode, final Integer digitsAfterDecimal, final BigDecimal principal, final BigDecimal inArrearsTolerance, final Integer numberOfRepayments, final Integer repaymentEvery, final BigDecimal interestRatePerPeriod, @@ -44,6 +45,7 @@ public class LoanProductCommand { this.name = name; this.description = description; this.fundId = fundId; + this.transactionProcessingStrategyId = transactionProcessingStrategyId; this.currencyCode = currencyCode; this.digitsAfterDecimal = digitsAfterDecimal; this.principal = principal; @@ -73,6 +75,10 @@ public class LoanProductCommand { public Long getFundId() { return fundId; } + + public Long getTransactionProcessingStrategyId() { + return transactionProcessingStrategyId; + } public String getCurrencyCode() { return currencyCode; @@ -133,6 +139,10 @@ public class LoanProductCommand { public boolean isFundChanged() { return this.modifiedParameters.contains("fundId"); } + + public boolean isTransactionProcessingStrategyChanged() { + return this.modifiedParameters.contains("transactionProcessingStrategyId"); + } public boolean isCurrencyCodeChanged() { return this.modifiedParameters.contains("currencyCode"); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanProductData.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanProductData.java index 0b1fdaac5..d8bd92ef8 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanProductData.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanProductData.java @@ -1,6 +1,5 @@ package org.mifosng.platform.api.data; -import java.io.Serializable; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collection; @@ -8,7 +7,7 @@ import java.util.List; import org.joda.time.DateTime; -public class LoanProductData implements Serializable { +public class LoanProductData { private Long id; private String name; @@ -16,6 +15,9 @@ public class LoanProductData implements Serializable { private Long fundId; private String fundName; + + private Long transactionProcessingStrategyId; + private String transactionProcessingStrategyName; private MoneyData principal; private MoneyData inArrearsTolerance; @@ -36,6 +38,7 @@ public class LoanProductData implements Serializable { private List currencyOptions = new ArrayList(); private Collection fundOptions = new ArrayList(); + private Collection transactionProcessingStrategyOptions = new ArrayList(); private List amortizationTypeOptions = new ArrayList(); private List interestTypeOptions = new ArrayList(); private List interestCalculationPeriodTypeOptions = new ArrayList(); @@ -55,7 +58,7 @@ public class LoanProductData implements Serializable { EnumOptionData interestRateFrequencyType, EnumOptionData amortizationType, EnumOptionData interestType, EnumOptionData interestCalculationPeriodType, Long fundId, - String fundName) { + String fundName, Long transactionProcessingStrategyId, String transactionProcessingStrategyName) { this.createdOn = createdOn; this.lastModifedOn = lastModifedOn; this.id = id; @@ -74,6 +77,8 @@ public class LoanProductData implements Serializable { this.interestCalculationPeriodType = interestCalculationPeriodType; this.fundId = fundId; this.fundName = fundName; + this.transactionProcessingStrategyId = transactionProcessingStrategyId; + this.transactionProcessingStrategyName = transactionProcessingStrategyName; } public Long getId() { @@ -115,6 +120,23 @@ public class LoanProductData implements Serializable { public void setFundName(String fundName) { this.fundName = fundName; } + + public Long getTransactionProcessingStrategyId() { + return transactionProcessingStrategyId; + } + + public void setTransactionProcessingStrategyId(Long transactionProcessingStrategyId) { + this.transactionProcessingStrategyId = transactionProcessingStrategyId; + } + + public String getTransactionProcessingStrategyName() { + return transactionProcessingStrategyName; + } + + public void setTransactionProcessingStrategyName( + String transactionProcessingStrategyName) { + this.transactionProcessingStrategyName = transactionProcessingStrategyName; + } public MoneyData getPrincipal() { return principal; @@ -255,6 +277,15 @@ public class LoanProductData implements Serializable { public void setFundOptions(Collection fundOptions) { this.fundOptions = fundOptions; } + + public Collection getTransactionProcessingStrategyOptions() { + return transactionProcessingStrategyOptions; + } + + public void setTransactionProcessingStrategyOptions( + Collection transactionProcessingStrategyOptions) { + this.transactionProcessingStrategyOptions = transactionProcessingStrategyOptions; + } public List getAmortizationTypeOptions() { return amortizationTypeOptions; diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/TransactionProcessingStrategyData.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/TransactionProcessingStrategyData.java new file mode 100644 index 000000000..1577a425a --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/TransactionProcessingStrategyData.java @@ -0,0 +1,27 @@ +package org.mifosng.platform.api.data; + + +public final class TransactionProcessingStrategyData { + + private final Long id; + private final String code; + private final String name; + + public TransactionProcessingStrategyData(final Long id, final String code, final String name) { + this.id = id; + this.code = code; + this.name = name; + } + + public Long getId() { + return id; + } + + public String getCode() { + return code; + } + + public String getName() { + return name; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionServiceImpl.java index aefc2881a..814ea66fe 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionServiceImpl.java @@ -226,12 +226,13 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService { @Override public String convertLoanProductDataToJson(final boolean prettyPrint, final Set responseParameters, final LoanProductData... products) { Set supportedParameters = new HashSet( - Arrays.asList("id", "name", "description", "fundId", "fundName", "principal", "inArrearsTolerance", "numberOfRepayments", + Arrays.asList("id", "name", "description", "fundId", "fundName", "transactionProcessingStrategyId", "transactionProcessingStrategyName", + "principal", "inArrearsTolerance", "numberOfRepayments", "repaymentEvery", "interestRatePerPeriod", "annualInterestRate", "repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "createdOn", "lastModifedOn", "currencyOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", - "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions") + "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "transactionProcessingStrategyOptions") ); final Set parameterNamesToSkip = new HashSet(); @@ -827,7 +828,7 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService { Map requestMap = gsonConverter.fromJson(json, typeOfMap); Set supportedParams = new HashSet( - Arrays.asList("name", "description", "fundId", "currencyCode", "digitsAfterDecimal", + Arrays.asList("name", "description", "fundId", "transactionProcessingStrategyId", "currencyCode", "digitsAfterDecimal", "principal", "inArrearsTolerance", "interestRatePerPeriod", "repaymentEvery", "numberOfRepayments", "repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "locale") ); @@ -839,6 +840,7 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService { String name = extractStringParameter("name", requestMap, modifiedParameters); String description = extractStringParameter("description", requestMap, modifiedParameters); Long fundId = extractLongParameter("fundId", requestMap, modifiedParameters); + Long transactionProcessingStrategyId = extractLongParameter("transactionProcessingStrategyId", requestMap, modifiedParameters); String currencyCode = extractStringParameter("currencyCode", requestMap, modifiedParameters); Integer digitsAfterDecimalValue = extractIntegerParameter("digitsAfterDecimal", requestMap, modifiedParameters); BigDecimal principalValue = extractBigDecimalParameter("principal", requestMap, modifiedParameters); @@ -854,7 +856,7 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService { Integer interestTypeValue = extractIntegerParameter("interestType", requestMap, modifiedParameters); Integer interestCalculationPeriodTypeValue = extractIntegerParameter("interestCalculationPeriodType", requestMap, modifiedParameters); - return new LoanProductCommand(modifiedParameters, resourceIdentifier, name, description, fundId, + return new LoanProductCommand(modifiedParameters, resourceIdentifier, name, description, fundId, transactionProcessingStrategyId, currencyCode, digitsAfterDecimalValue, principalValue, inArrearsToleranceValue, numberOfRepaymentsValue, repaymentEveryValue, interestRatePerPeriodValue, repaymentFrequencyTypeValue, interestRateFrequencyTypeValue, amortizationTypeValue, interestTypeValue, interestCalculationPeriodTypeValue); } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/LoanTransactionProcessingStrategyNotFoundException.java b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/LoanTransactionProcessingStrategyNotFoundException.java new file mode 100644 index 000000000..7aedebeaf --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/LoanTransactionProcessingStrategyNotFoundException.java @@ -0,0 +1,11 @@ +package org.mifosng.platform.exceptions; + +/** + * A {@link RuntimeException} thrown when loan transactions processing strategy resources are not found. + */ +public class LoanTransactionProcessingStrategyNotFoundException extends AbstractPlatformResourceNotFoundException { + + public LoanTransactionProcessingStrategyNotFoundException(final Long id) { + super("error.msg.transactions.processing.strategy.id.invalid", "Loan transaction processing strategy with identifier " + id + " does not exist", id); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanProduct.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanProduct.java index 15f1cf01f..14a9bc56d 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanProduct.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanProduct.java @@ -32,6 +32,10 @@ public class LoanProduct extends AbstractAuditableCustom { @ManyToOne @JoinColumn(name = "fund_id", nullable = true) private Fund fund; + + @ManyToOne + @JoinColumn(name = "loan_transaction_strategy_id", nullable = true) + private LoanTransactionProcessingStrategy transactionProcessingStrategy; @Column(name = "name", nullable = false) private String name; @@ -49,12 +53,14 @@ public class LoanProduct extends AbstractAuditableCustom { this.loanProductRelatedDetail = null; } - public LoanProduct(final Fund fund, final String name, final String description, final MonetaryCurrency currency, final BigDecimal defaultPrincipal, + public LoanProduct(final Fund fund, final LoanTransactionProcessingStrategy transactionProcessingStrategy, + final String name, final String description, final MonetaryCurrency currency, final BigDecimal defaultPrincipal, final BigDecimal defaultNominalInterestRatePerPeriod, final PeriodFrequencyType interestPeriodFrequencyType, final BigDecimal defaultAnnualNominalInterestRate, final InterestMethod interestMethod, final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repayEvery, final PeriodFrequencyType repaymentFrequencyType, final Integer defaultNumberOfInstallments, final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance) { this.fund = fund; + this.transactionProcessingStrategy = transactionProcessingStrategy; this.name = name.trim(); if (StringUtils.isNotBlank(description)) { this.description = description.trim(); @@ -96,10 +102,6 @@ public class LoanProduct extends AbstractAuditableCustom { return this.loanProductRelatedDetail.isInterestRebateAllowed(); } - public boolean identifiedBy(final String identifier) { - return identifier.equalsIgnoreCase(this.name); - } - public BigDecimal getDefaultNominalInterestRatePerPeriod() { return this.loanProductRelatedDetail.getNominalInterestRatePerPeriod(); } @@ -131,8 +133,12 @@ public class LoanProduct extends AbstractAuditableCustom { public Fund getFund() { return fund; } + + public LoanTransactionProcessingStrategy getTransactionProcessingStrategy() { + return transactionProcessingStrategy; + } - public void update(final LoanProductCommand command, final Fund fund) { + public void update(final LoanProductCommand command, final Fund fund, final LoanTransactionProcessingStrategy strategy) { if (command.isNameChanged()) { this.name = command.getName(); @@ -146,6 +152,10 @@ public class LoanProduct extends AbstractAuditableCustom { this.fund = fund; } + if (command.isTransactionProcessingStrategyChanged()) { + this.transactionProcessingStrategy = strategy; + } + this.loanProductRelatedDetail.update(command); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanTransactionProcessingStrategy.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanTransactionProcessingStrategy.java new file mode 100644 index 000000000..94e913926 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanTransactionProcessingStrategy.java @@ -0,0 +1,35 @@ +package org.mifosng.platform.loan.domain; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +import org.mifosng.platform.api.data.TransactionProcessingStrategyData; +import org.mifosng.platform.infrastructure.AbstractAuditableCustom; +import org.mifosng.platform.user.domain.AppUser; + +/** + * + */ +@Entity +@Table(name = "ref_loan_transaction_processing_strategy") +public class LoanTransactionProcessingStrategy extends AbstractAuditableCustom { + + @Column(name = "code", unique=true) + private String code; + + @Column(name = "name") + private String name; + + protected LoanTransactionProcessingStrategy() { + // + } + + public String code() { + return this.code; + } + + public TransactionProcessingStrategyData toData() { + return new TransactionProcessingStrategyData(this.getId(), this.code, this.name); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanTransactionProcessingStrategyRepository.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanTransactionProcessingStrategyRepository.java new file mode 100644 index 000000000..41c47e77c --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanTransactionProcessingStrategyRepository.java @@ -0,0 +1,9 @@ +package org.mifosng.platform.loan.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface LoanTransactionProcessingStrategyRepository extends JpaRepository, + JpaSpecificationExecutor { + // no added behaviour +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanDropdownReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanDropdownReadPlatformService.java index 8ac1e9917..36ef5fa09 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanDropdownReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanDropdownReadPlatformService.java @@ -1,8 +1,10 @@ package org.mifosng.platform.loanproduct.service; +import java.util.Collection; import java.util.List; import org.mifosng.platform.api.data.EnumOptionData; +import org.mifosng.platform.api.data.TransactionProcessingStrategyData; public interface LoanDropdownReadPlatformService { @@ -15,4 +17,6 @@ public interface LoanDropdownReadPlatformService { List retrieveRepaymentFrequencyTypeOptions(); List retrieveInterestRateFrequencyTypeOptions(); + + Collection retreiveTransactionProcessingStrategies(); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java index ecd042b2b..a602c7852 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java @@ -6,20 +6,32 @@ import static org.mifosng.platform.loanproduct.service.LoanEnumerations.interest import static org.mifosng.platform.loanproduct.service.LoanEnumerations.interestType; import static org.mifosng.platform.loanproduct.service.LoanEnumerations.repaymentFrequencyType; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; import org.mifosng.platform.api.data.EnumOptionData; +import org.mifosng.platform.api.data.TransactionProcessingStrategyData; import org.mifosng.platform.loan.domain.AmortizationMethod; import org.mifosng.platform.loan.domain.InterestCalculationPeriodMethod; import org.mifosng.platform.loan.domain.InterestMethod; +import org.mifosng.platform.loan.domain.LoanTransactionProcessingStrategy; +import org.mifosng.platform.loan.domain.LoanTransactionProcessingStrategyRepository; import org.mifosng.platform.loan.domain.PeriodFrequencyType; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service -public class LoanDropdownReadPlatformServiceImpl implements - LoanDropdownReadPlatformService { +public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlatformService { + private final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository; + + @Autowired + public LoanDropdownReadPlatformServiceImpl(final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository) { + this.loanTransactionProcessingStrategyRepository = loanTransactionProcessingStrategyRepository; + } + @Override public List retrieveLoanAmortizationTypeOptions() { @@ -67,4 +79,17 @@ public class LoanDropdownReadPlatformServiceImpl implements interestRateFrequencyType(PeriodFrequencyType.YEARS)); return interestRateFrequencyTypeOptions; } + + @Override + public Collection retreiveTransactionProcessingStrategies() { + + Collection strategyOptions = new ArrayList(); + + List strategies = this.loanTransactionProcessingStrategyRepository.findAll(); + for (LoanTransactionProcessingStrategy strategy : strategies) { + strategyOptions.add(strategy.toData()); + } + + return strategyOptions; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductReadPlatformServiceImpl.java index 908eb0a80..38fee39da 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductReadPlatformServiceImpl.java @@ -13,6 +13,7 @@ import org.mifosng.platform.api.data.FundData; import org.mifosng.platform.api.data.LoanProductData; import org.mifosng.platform.api.data.LoanProductLookup; import org.mifosng.platform.api.data.MoneyData; +import org.mifosng.platform.api.data.TransactionProcessingStrategyData; import org.mifosng.platform.currency.service.CurrencyReadPlatformService; import org.mifosng.platform.exceptions.LoanProductNotFoundException; import org.mifosng.platform.fund.service.FundReadPlatformService; @@ -128,14 +129,12 @@ public class LoanProductReadPlatformServiceImpl implements private static final class LoanProductMapper implements RowMapper { - // private final List allowedCurrencies; - // private final Collection allFunds; - public LoanProductMapper() { } public String loanProductSchema() { - return "lp.id as id, lp.fund_id as fundId, f.name as fundName, lp.name as name, lp.description as description, lp.flexible_repayment_schedule as isFlexible, lp.interest_rebate as isInterestRebateAllowed, " + return "lp.id as id, lp.fund_id as fundId, f.name as fundName, lp.loan_transaction_strategy_id as transactionStrategyId, ltps.name as transactionStrategyName, " + + "lp.name as name, lp.description as description, lp.flexible_repayment_schedule as isFlexible, lp.interest_rebate as isInterestRebateAllowed, " + "lp.principal_amount as principal, lp.currency_code as currencyCode, lp.currency_digits as currencyDigits, " + "lp.nominal_interest_rate_per_period as interestRatePerPeriod, lp.interest_period_frequency_enum as interestRatePerPeriodFreq, " + "lp.annual_nominal_interest_rate as annualInterestRate, lp.interest_method_enum as interestMethod, lp.interest_calculated_in_period_enum as interestCalculationInPeriodMethod," @@ -145,6 +144,7 @@ public class LoanProductReadPlatformServiceImpl implements + "curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol " + " from portfolio_product_loan lp " + " left join org_fund f on f.id = lp.fund_id" + + " left join ref_loan_transaction_processing_strategy ltps on ltps.id = lp.loan_transaction_strategy_id" + " join ref_currency curr on curr.code = lp.currency_code"; } @@ -158,6 +158,9 @@ public class LoanProductReadPlatformServiceImpl implements Long fundId = JdbcSupport.getLong(rs, "fundId"); String fundName = rs.getString("fundName"); + + Long transactionStrategyId = JdbcSupport.getLong(rs, "transactionStrategyId"); + String transactionStrategyName = rs.getString("transactionStrategyName"); String currencyCode = rs.getString("currencyCode"); String currencyName = rs.getString("currencyName"); @@ -217,7 +220,7 @@ public class LoanProductReadPlatformServiceImpl implements numberOfRepayments, repaymentEvery, interestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType, interestType, - interestCalculationPeriodType, fundId, fundName); + interestCalculationPeriodType, fundId, fundName, transactionStrategyId, transactionStrategyName); } } @@ -241,35 +244,26 @@ public class LoanProductReadPlatformServiceImpl implements } - private void populateProductDataWithDropdownOptions( - LoanProductData productData) { + private void populateProductDataWithDropdownOptions(final LoanProductData productData) { - List currencyOptions = currencyReadPlatformService - .retrieveAllowedCurrencies(); - List amortizationTypeOptions = dropdownReadPlatformService - .retrieveLoanAmortizationTypeOptions(); - List interestTypeOptions = dropdownReadPlatformService - .retrieveLoanInterestTypeOptions(); - List interestCalculationPeriodTypeOptions = dropdownReadPlatformService - .retrieveLoanInterestRateCalculatedInPeriodOptions(); - List repaymentFrequencyTypeOptions = dropdownReadPlatformService - .retrieveRepaymentFrequencyTypeOptions(); - List interestRateFrequencyTypeOptions = dropdownReadPlatformService - .retrieveInterestRateFrequencyTypeOptions(); + List currencyOptions = currencyReadPlatformService.retrieveAllowedCurrencies(); + List amortizationTypeOptions = dropdownReadPlatformService.retrieveLoanAmortizationTypeOptions(); + List interestTypeOptions = dropdownReadPlatformService.retrieveLoanInterestTypeOptions(); + List interestCalculationPeriodTypeOptions = dropdownReadPlatformService.retrieveLoanInterestRateCalculatedInPeriodOptions(); + List repaymentFrequencyTypeOptions = dropdownReadPlatformService.retrieveRepaymentFrequencyTypeOptions(); + List interestRateFrequencyTypeOptions = dropdownReadPlatformService.retrieveInterestRateFrequencyTypeOptions(); - Collection fundOptions = this.fundReadPlatformService - .retrieveAllFunds(); + Collection fundOptions = this.fundReadPlatformService.retrieveAllFunds(); + Collection transactionProcessingStrategyOptions = this.dropdownReadPlatformService.retreiveTransactionProcessingStrategies(); productData.setCurrencyOptions(currencyOptions); productData.setAmortizationTypeOptions(amortizationTypeOptions); productData.setInterestTypeOptions(interestTypeOptions); - productData - .setInterestCalculationPeriodTypeOptions(interestCalculationPeriodTypeOptions); - productData - .setRepaymentFrequencyTypeOptions(repaymentFrequencyTypeOptions); - productData - .setInterestRateFrequencyTypeOptions(interestRateFrequencyTypeOptions); + productData.setInterestCalculationPeriodTypeOptions(interestCalculationPeriodTypeOptions); + productData.setRepaymentFrequencyTypeOptions(repaymentFrequencyTypeOptions); + productData.setInterestRateFrequencyTypeOptions(interestRateFrequencyTypeOptions); productData.setFundOptions(fundOptions); + productData.setTransactionProcessingStrategyOptions(transactionProcessingStrategyOptions); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java index 1873c6ca4..fcad0d3c6 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java @@ -7,6 +7,7 @@ import org.mifosng.platform.api.data.EntityIdentifier; import org.mifosng.platform.currency.domain.MonetaryCurrency; import org.mifosng.platform.exceptions.FundNotFoundException; import org.mifosng.platform.exceptions.LoanProductNotFoundException; +import org.mifosng.platform.exceptions.LoanTransactionProcessingStrategyNotFoundException; import org.mifosng.platform.fund.domain.Fund; import org.mifosng.platform.fund.domain.FundRepository; import org.mifosng.platform.loan.domain.AmortizationMethod; @@ -14,6 +15,8 @@ import org.mifosng.platform.loan.domain.InterestCalculationPeriodMethod; import org.mifosng.platform.loan.domain.InterestMethod; import org.mifosng.platform.loan.domain.LoanProduct; import org.mifosng.platform.loan.domain.LoanProductRepository; +import org.mifosng.platform.loan.domain.LoanTransactionProcessingStrategy; +import org.mifosng.platform.loan.domain.LoanTransactionProcessingStrategyRepository; import org.mifosng.platform.loan.domain.PeriodFrequencyType; import org.mifosng.platform.loanschedule.domain.AprCalculator; import org.mifosng.platform.security.PlatformSecurityContext; @@ -28,14 +31,16 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro private final LoanProductRepository loanProductRepository; private final AprCalculator aprCalculator; private final FundRepository fundRepository; + private final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository; @Autowired public LoanProductWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final LoanProductRepository loanProductRepository, - final AprCalculator aprCalculator, final FundRepository fundRepository) { + final AprCalculator aprCalculator, final FundRepository fundRepository, final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository) { this.context = context; this.loanProductRepository = loanProductRepository; this.aprCalculator = aprCalculator; this.fundRepository = fundRepository; + this.loanTransactionProcessingStrategyRepository = loanTransactionProcessingStrategyRepository; } @Transactional @@ -65,8 +70,10 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro // associating fund with loan product at creation is optional for now. Fund fund = findFundByIdIfProvided(command.getFundId()); + LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(command.getTransactionProcessingStrategyId()); - LoanProduct loanproduct = new LoanProduct(fund, command.getName(), command.getDescription(), + LoanProduct loanproduct = new LoanProduct(fund, loanTransactionProcessingStrategy, + command.getName(), command.getDescription(), currency, command.getPrincipal(), command.getInterestRatePerPeriod(), interestFrequencyType, annualInterestRate, interestMethod, interestCalculationPeriodMethod, command.getRepaymentEvery(), repaymentFrequencyType, command.getNumberOfRepayments(), @@ -77,6 +84,17 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro return new EntityIdentifier(loanproduct.getId()); } + private LoanTransactionProcessingStrategy findStrategyByIdIfProvided(final Long transactionProcessingStrategyId) { + LoanTransactionProcessingStrategy fund = null; + if (transactionProcessingStrategyId != null) { + fund = this.loanTransactionProcessingStrategyRepository.findOne(transactionProcessingStrategyId); + if (fund == null) { + throw new LoanTransactionProcessingStrategyNotFoundException(transactionProcessingStrategyId); + } + } + return fund; + } + private Fund findFundByIdIfProvided(final Long fundId) { Fund fund = null; if (fundId != null) { @@ -104,8 +122,9 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro // associating fund with loan product at creation is optional for now. Fund fund = findFundByIdIfProvided(command.getFundId()); + LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(command.getTransactionProcessingStrategyId()); - product.update(command, fund); + product.update(command, fund, loanTransactionProcessingStrategy); this.loanProductRepository.save(product);