From ccdda4287bc195c6c44ae770badf58940fa27cf2 Mon Sep 17 00:00:00 2001 From: Keith Woodlock Date: Tue, 23 Oct 2012 11:52:45 +0100 Subject: [PATCH] MIFOSX-90: detect in active charges on product during loan creation. --- .../ChargeDropdownReadPlatformService.java | 15 ++ ...ChargeDropdownReadPlatformServiceImpl.java | 38 +++++ .../ChargeReadPlatformServiceImpl.java | 138 ++++++++---------- .../ChargeIsNotActiveException.java | 13 +- .../platform/loan/service/LoanAssembler.java | 10 +- .../loan/service/LoanChargeAssembler.java | 5 + ...WritePlatformServiceJpaRepositoryImpl.java | 7 +- ...WritePlatformServiceJpaRepositoryImpl.java | 2 +- 8 files changed, 132 insertions(+), 96 deletions(-) create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/charge/service/ChargeDropdownReadPlatformService.java create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/charge/service/ChargeDropdownReadPlatformServiceImpl.java diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/charge/service/ChargeDropdownReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/charge/service/ChargeDropdownReadPlatformService.java new file mode 100644 index 000000000..3b30a5f83 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/charge/service/ChargeDropdownReadPlatformService.java @@ -0,0 +1,15 @@ +package org.mifosng.platform.charge.service; + +import java.util.List; + +import org.mifosng.platform.api.data.EnumOptionData; + +public interface ChargeDropdownReadPlatformService { + + List retrieveCalculationTypes(); + + List retrieveApplicableToTypes(); + + List retrieveCollectionTimeTypes(); + +} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/charge/service/ChargeDropdownReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/charge/service/ChargeDropdownReadPlatformServiceImpl.java new file mode 100644 index 000000000..f87c7edd3 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/charge/service/ChargeDropdownReadPlatformServiceImpl.java @@ -0,0 +1,38 @@ +package org.mifosng.platform.charge.service; + +import static org.mifosng.platform.charge.service.ChargeEnumerations.chargeAppliesTo; +import static org.mifosng.platform.charge.service.ChargeEnumerations.chargeCalculationType; +import static org.mifosng.platform.charge.service.ChargeEnumerations.chargeTimeType; + +import java.util.Arrays; +import java.util.List; + +import org.mifosng.platform.api.data.EnumOptionData; +import org.mifosng.platform.charge.domain.ChargeAppliesTo; +import org.mifosng.platform.charge.domain.ChargeCalculationType; +import org.mifosng.platform.charge.domain.ChargeTimeType; +import org.springframework.stereotype.Service; + +@Service +public class ChargeDropdownReadPlatformServiceImpl implements ChargeDropdownReadPlatformService { + + @Override + public List retrieveCalculationTypes() { + + return Arrays.asList(chargeCalculationType(ChargeCalculationType.FLAT), + chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT) + // chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST), + // chargeCalculationType(ChargeCalculationType.PERCENT_OF_INTEREST) + ); + } + + @Override + public List retrieveApplicableToTypes() { + return Arrays.asList(chargeAppliesTo(ChargeAppliesTo.LOAN)); + } + + @Override + public List retrieveCollectionTimeTypes() { + return Arrays.asList(chargeTimeType(ChargeTimeType.DISBURSEMENT)); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/charge/service/ChargeReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/charge/service/ChargeReadPlatformServiceImpl.java index 5813da4f2..718f303e0 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/charge/service/ChargeReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/charge/service/ChargeReadPlatformServiceImpl.java @@ -1,12 +1,16 @@ package org.mifosng.platform.charge.service; +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; +import java.util.List; + import org.mifosng.platform.api.data.ChargeData; import org.mifosng.platform.api.data.CurrencyData; import org.mifosng.platform.api.data.EnumOptionData; import org.mifosng.platform.api.data.LoanChargeData; import org.mifosng.platform.charge.domain.ChargeAppliesTo; -import org.mifosng.platform.charge.domain.ChargeCalculationType; -import org.mifosng.platform.charge.domain.ChargeTimeType; import org.mifosng.platform.currency.service.CurrencyReadPlatformService; import org.mifosng.platform.exceptions.ChargeNotFoundException; import org.mifosng.platform.infrastructure.JdbcSupport; @@ -18,55 +22,47 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Service; -import java.math.BigDecimal; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - -import static org.mifosng.platform.charge.service.ChargeEnumerations.chargeAppliesTo; -import static org.mifosng.platform.charge.service.ChargeEnumerations.chargeCalculationType; -import static org.mifosng.platform.charge.service.ChargeEnumerations.chargeTimeType; - @Service public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService { private final JdbcTemplate jdbcTemplate; private final PlatformSecurityContext context; private final CurrencyReadPlatformService currencyReadPlatformService; - - @Autowired - public ChargeReadPlatformServiceImpl(PlatformSecurityContext context, - final CurrencyReadPlatformService currencyReadPlatformService, - final TenantAwareRoutingDataSource dataSource) { - this.context = context; - this.jdbcTemplate = new JdbcTemplate(dataSource); - this.currencyReadPlatformService = currencyReadPlatformService; - } + private final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService; + + @Autowired + public ChargeReadPlatformServiceImpl( + final PlatformSecurityContext context, + final CurrencyReadPlatformService currencyReadPlatformService, + final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService, + final TenantAwareRoutingDataSource dataSource) { + this.context = context; + this.chargeDropdownReadPlatformService = chargeDropdownReadPlatformService; + this.jdbcTemplate = new JdbcTemplate(dataSource); + this.currencyReadPlatformService = currencyReadPlatformService; + } @Override public Collection retrieveAllCharges() { this.context.authenticatedUser(); - ChargeMapper rm = new ChargeMapper(); + final ChargeMapper rm = new ChargeMapper(); - String sql = "select " + rm.chargeSchema() + " where c.is_deleted=0 order by c.name "; + final String sql = "select " + rm.chargeSchema() + " where c.is_deleted=0 order by c.name "; return this.jdbcTemplate.query(sql, rm, new Object[] {}); } @Override - public ChargeData retrieveCharge(Long chargeId) { + public ChargeData retrieveCharge(final Long chargeId) { try { this.context.authenticatedUser(); - ChargeMapper rm = new ChargeMapper(); + final ChargeMapper rm = new ChargeMapper(); - String sql = "select " + rm.chargeSchema() + " where c.id = ? and c.is_deleted=0 "; + final String sql = "select " + rm.chargeSchema() + " where c.id = ? and c.is_deleted=0 "; - ChargeData chargeData = this.jdbcTemplate.queryForObject(sql, rm, new Object[] {chargeId}); - return chargeData; + return this.jdbcTemplate.queryForObject(sql, rm, new Object[] {chargeId}); } catch (EmptyResultDataAccessException e){ throw new ChargeNotFoundException(chargeId); } @@ -77,19 +73,11 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService this.context.authenticatedUser(); - List currencyOptions = currencyReadPlatformService.retrieveAllowedCurrencies(); - - List allowedChargeCalculationTypeOptions = Arrays.asList( - chargeCalculationType(ChargeCalculationType.FLAT), - chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT), - chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST), - chargeCalculationType(ChargeCalculationType.PERCENT_OF_INTEREST) - ); - - List allowedChargeAppliesToOptions = Arrays.asList(chargeAppliesTo(ChargeAppliesTo.LOAN)); - - List allowedChargeTimeOptions = Arrays.asList(chargeTimeType(ChargeTimeType.DISBURSEMENT)); - + final List currencyOptions = currencyReadPlatformService.retrieveAllowedCurrencies(); + final List allowedChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService.retrieveCalculationTypes(); + final List allowedChargeAppliesToOptions = this.chargeDropdownReadPlatformService.retrieveApplicableToTypes(); + final List allowedChargeTimeOptions = this.chargeDropdownReadPlatformService.retrieveCollectionTimeTypes(); + return ChargeData.template(currencyOptions, allowedChargeCalculationTypeOptions, allowedChargeAppliesToOptions, allowedChargeTimeOptions); } @@ -99,9 +87,9 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService this.context.authenticatedUser(); - ChargeMapper rm = new ChargeMapper(); + final ChargeMapper rm = new ChargeMapper(); - String sql = "select " + rm.loanProductChargeSchema() + " where c.is_deleted=0 and plc.product_loan_id=?"; + final String sql = "select " + rm.loanProductChargeSchema() + " where c.is_deleted=0 and plc.product_loan_id=?"; return this.jdbcTemplate.query(sql, rm, new Object[] {loanProductId}); } @@ -110,9 +98,9 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService public Collection retrieveLoanCharges(Long loanId) { this.context.authenticatedUser(); - LoanChargeMapper rm = new LoanChargeMapper(); + final LoanChargeMapper rm = new LoanChargeMapper(); - String sql = "select " + rm.loanChargeSchema() + " where c.is_deleted=0 and lc.loan_id=?"; + final String sql = "select " + rm.loanChargeSchema() + " where c.is_deleted=0 and lc.loan_id=?"; return this.jdbcTemplate.query(sql, rm, new Object[] {loanId}); } @@ -121,9 +109,9 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService public Collection retrieveLoanApplicableCharges() { this.context.authenticatedUser(); - ChargeMapper rm = new ChargeMapper(); + final ChargeMapper rm = new ChargeMapper(); - String sql = "select " + rm.chargeSchema() + " where c.is_deleted=0 and c.is_active=1 and c.charge_applies_to_enum=? order by c.name "; + final String sql = "select " + rm.chargeSchema() + " where c.is_deleted=0 and c.is_active=1 and c.charge_applies_to_enum=? order by c.name "; return this.jdbcTemplate.query(sql, rm, new Object[] {ChargeAppliesTo.LOAN.getValue()}); } @@ -132,17 +120,10 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService public ChargeData retrieveLoanChargeTemplate() { this.context.authenticatedUser(); - List allowedChargeCalculationTypeOptions = Arrays.asList( - chargeCalculationType(ChargeCalculationType.FLAT), - chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT), - chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST), - chargeCalculationType(ChargeCalculationType.PERCENT_OF_INTEREST) - ); - - List allowedChargeTimeOptions = Arrays.asList(chargeTimeType(ChargeTimeType.DISBURSEMENT)); - - return ChargeData.template(null, allowedChargeCalculationTypeOptions, - null, allowedChargeTimeOptions); + final List allowedChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService.retrieveCalculationTypes(); + final List allowedChargeTimeOptions = this.chargeDropdownReadPlatformService.retrieveCollectionTimeTypes(); + + return ChargeData.template(null, allowedChargeCalculationTypeOptions, null, allowedChargeTimeOptions); } private static final class ChargeMapper implements RowMapper { @@ -160,33 +141,30 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService return chargeSchema() + " join m_product_loan_charge plc on plc.charge_id = c.id"; } - - @Override - public ChargeData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException { - Long id = rs.getLong("id"); - String name = rs.getString("name"); - BigDecimal amount = rs.getBigDecimal("amount"); + public ChargeData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + final Long id = rs.getLong("id"); + final String name = rs.getString("name"); + final BigDecimal amount = rs.getBigDecimal("amount"); - String currencyCode = rs.getString("currencyCode"); - String currencyName = rs.getString("currencyName"); - String currencyNameCode = rs.getString("currencyNameCode"); - String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol"); - Integer currencyDecimalPlaces = JdbcSupport.getInteger(rs, "currencyDecimalPlaces"); + final String currencyCode = rs.getString("currencyCode"); + final String currencyName = rs.getString("currencyName"); + final String currencyNameCode = rs.getString("currencyNameCode"); + final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol"); + final Integer currencyDecimalPlaces = JdbcSupport.getInteger(rs, "currencyDecimalPlaces"); - CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDecimalPlaces, + final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDecimalPlaces, currencyDisplaySymbol, currencyNameCode); - int chargeAppliesTo = rs.getInt("chargeAppliesTo"); - EnumOptionData chargeAppliesToType = ChargeEnumerations.chargeAppliesTo(chargeAppliesTo); + final int chargeAppliesTo = rs.getInt("chargeAppliesTo"); + final EnumOptionData chargeAppliesToType = ChargeEnumerations.chargeAppliesTo(chargeAppliesTo); - int chargeTime = rs.getInt("chargeTime"); - EnumOptionData chargeTimeType = ChargeEnumerations.chargeTimeType(chargeTime); + final int chargeTime = rs.getInt("chargeTime"); + final EnumOptionData chargeTimeType = ChargeEnumerations.chargeTimeType(chargeTime); - int chargeCalculation = rs.getInt("chargeCalculation"); - EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(chargeCalculation); - - boolean active = rs.getBoolean("active"); + final int chargeCalculation = rs.getInt("chargeCalculation"); + final EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(chargeCalculation); + final boolean active = rs.getBoolean("active"); return new ChargeData(id, name, amount, currency, chargeTimeType, chargeAppliesToType, chargeCalculationType, active); } @@ -241,4 +219,4 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService return new LoanChargeData(id, chargeId, name, currency, amount, amountPaid, amountOutstanding, chargeTimeType, chargeCalculationType, percentageOf, amountPercentageAppliedTo); } } -} +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/ChargeIsNotActiveException.java b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/ChargeIsNotActiveException.java index f2f6d7605..eb450c7bc 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/ChargeIsNotActiveException.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/ChargeIsNotActiveException.java @@ -1,12 +1,11 @@ package org.mifosng.platform.exceptions; /** - * {@link AbstractPlatformDomainRuleException} thrown when charge is not active + * {@link AbstractPlatformDomainRuleException} thrown when charge is not active. */ -public class ChargeIsNotActiveException extends AbstractPlatformDomainRuleException{ +public class ChargeIsNotActiveException extends AbstractPlatformDomainRuleException { - public ChargeIsNotActiveException(final Long id) { - super("error.msg.charge.is.not.active", "Charge with identifier " + id + " is not active", id); - } - -} + public ChargeIsNotActiveException(final Long id, final String name) { + super("error.msg.charge.is.not.active", "Charge '" + name + "' with identifier " + id + " is not active", name, id); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanAssembler.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanAssembler.java index 9dadc5253..5604d0e0f 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanAssembler.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanAssembler.java @@ -97,18 +97,18 @@ public class LoanAssembler { } } - MonetaryCurrency currency = loanProduct.getCurrency(); + final MonetaryCurrency currency = loanProduct.getCurrency(); final Integer loanTermFrequency = command.getLoanTermFrequency(); final PeriodFrequencyType loanTermFrequencyType = PeriodFrequencyType.fromInt(command.getLoanTermFrequencyType()); - LoanProductRelatedDetail loanRepaymentScheduleDetail = assembleLoanProductRelatedDetailFrom(command, currency); + final LoanProductRelatedDetail loanRepaymentScheduleDetail = assembleLoanProductRelatedDetailFrom(command, currency); // associating fund with loan product at creation is optional for now. - Fund fund = findFundByIdIfProvided(command.getFundId()); - LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(command.getTransactionProcessingStrategyId()); + final Fund fund = findFundByIdIfProvided(command.getFundId()); + final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(command.getTransactionProcessingStrategyId()); //optionally associate a loan officer to the loan - Staff loanOfficer= findLoanOfficerByIdIfProvided(command.getLoanOfficerId()); + final Staff loanOfficer= findLoanOfficerByIdIfProvided(command.getLoanOfficerId()); // optionally, see if charges are associated with loan on creation (through loan product or by being directly added) final Set loanCharges = this.loanChargeAssembler.assembleFrom(command.getCharges(), loanProduct.getCharges(), command.getPrincipal()); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanChargeAssembler.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanChargeAssembler.java index 6bf7cb88e..5fb12b227 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanChargeAssembler.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanChargeAssembler.java @@ -7,6 +7,7 @@ import java.util.Set; import org.mifosng.platform.api.commands.LoanChargeCommand; import org.mifosng.platform.charge.domain.Charge; import org.mifosng.platform.charge.domain.ChargeRepository; +import org.mifosng.platform.exceptions.ChargeIsNotActiveException; import org.mifosng.platform.exceptions.ChargeNotFoundException; import org.mifosng.platform.loan.domain.LoanCharge; import org.mifosng.platform.loan.domain.LoanChargeRepository; @@ -37,6 +38,10 @@ public class LoanChargeAssembler { if (chargeDefinition == null || chargeDefinition.isDeleted()) { throw new ChargeNotFoundException(chargeDefinitionId); } + + if (!chargeDefinition.isActive()) { + throw new ChargeIsNotActiveException(chargeDefinitionId, chargeDefinition.getName()); + } final LoanCharge loanCharge = LoanCharge.createNewWithoutLoan(chargeDefinition, loanChargeCommand, loanPrincipal); loanCharges.add(loanCharge); } else { diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformServiceJpaRepositoryImpl.java index 2898ab7a4..d377f5bfe 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -643,11 +643,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf throw new ChargeNotFoundException(command.getChargeId()); } - LoanCharge loanCharge = LoanCharge.createNew(loan, chargeDefinition, command); - if (!chargeDefinition.isActive()) { - throw new ChargeIsNotActiveException(chargeDefinition.getId()); + throw new ChargeIsNotActiveException(chargeDefinition.getId(), chargeDefinition.getName()); } + + final LoanCharge loanCharge = LoanCharge.createNew(loan, chargeDefinition, command); if (!loan.hasCurrencyCodeOf(chargeDefinition.getCurrencyCode())){ String errorMessage = "Charge and Loan must have the same currency."; @@ -656,6 +656,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf this.loanChargeRepository.saveAndFlush(loanCharge); + // FIXME - KW - loan.getCharges().add(loanCharge); loan.updateTotalChargesDueAtDisbursement(); 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 2ab02c652..9d000b126 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 @@ -171,7 +171,7 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro throw new ChargeNotFoundException(id); } if (!charge.isActive()){ - throw new ChargeIsNotActiveException(id); + throw new ChargeIsNotActiveException(id, charge.getName()); } if (!loanProductCurrencyCode.equals(charge.getCurrencyCode())){ String errorMessage = "Charge and Loan Product must have the same currency.";