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 6be6d5cc1..30f9cc3fc 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 @@ -18,11 +18,13 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import org.mifosng.platform.api.commands.LoanProductCommand; +import org.mifosng.platform.api.data.ChargeData; import org.mifosng.platform.api.data.EntityIdentifier; import org.mifosng.platform.api.data.LoanProductData; import org.mifosng.platform.api.infrastructure.ApiDataConversionService; import org.mifosng.platform.api.infrastructure.ApiJsonSerializerService; import org.mifosng.platform.api.infrastructure.ApiParameterHelper; +import org.mifosng.platform.charge.service.ChargeReadPlatformService; import org.mifosng.platform.loanproduct.service.LoanProductReadPlatformService; import org.mifosng.platform.loanproduct.service.LoanProductWritePlatformService; import org.springframework.beans.factory.annotation.Autowired; @@ -40,6 +42,9 @@ public class LoanProductsApiResource { @Autowired private LoanProductWritePlatformService loanProductWritePlatformService; + @Autowired + private ChargeReadPlatformService chargeReadPlatformService; + @Autowired private ApiDataConversionService apiDataConversionService; @@ -67,7 +72,7 @@ public class LoanProductsApiResource { Arrays.asList("id", "name", "description", "fundId", "fundName", "principal", "inArrearsTolerance", "numberOfRepayments", "repaymentEvery", "interestRatePerPeriod", "annualInterestRate", "repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", - "createdOn", "lastModifedOn") + "charges", "createdOn", "lastModifedOn") ); Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); @@ -97,9 +102,9 @@ public class LoanProductsApiResource { Arrays.asList("id", "name", "description", "fundId", "fundName", "transactionProcessingStrategyId", "transactionProcessingStrategyName", "principal", "inArrearsTolerance", "numberOfRepayments", "repaymentEvery", "interestRatePerPeriod", "annualInterestRate", - "repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", + "repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "charges", "createdOn", "lastModifedOn","currencyOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", - "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "transactionProcessingStrategyOptions") + "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "transactionProcessingStrategyOptions", "chargeOptions") ); Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); @@ -124,7 +129,8 @@ public class LoanProductsApiResource { "transactionProcessingStrategyId", "transactionProcessingStrategyName", "principal", "inArrearsTolerance", "numberOfRepayments", "repaymentEvery", "interestRatePerPeriod", "annualInterestRate", - "repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", + "repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType", + "interestCalculationPeriodType", "charges", "createdOn", "lastModifedOn") ); @@ -138,7 +144,10 @@ public class LoanProductsApiResource { LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId); if (template) { responseParameters.addAll(Arrays.asList("currencyOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", - "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "transactionProcessingStrategyOptions")); + "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "transactionProcessingStrategyOptions", "chargeOptions")); + Collection chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(); + chargeOptions.removeAll(loanProduct.getCharges()); + loanProduct.setChargeOptions(chargeOptions); } return this.apiJsonSerializerService.serializeLoanProductDataToJson(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 467b15a16..8743e435c 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 @@ -30,7 +30,9 @@ public class LoanProductCommand { private final Integer amortizationType; private final Integer interestType; private final Integer interestCalculationPeriodType; - + + private final String[] charges; + private final Set modifiedParameters; public LoanProductCommand(final Set modifiedParameters, final Long id, final String name, final String description, @@ -39,7 +41,7 @@ public class LoanProductCommand { final BigDecimal principal, final BigDecimal inArrearsTolerance, final Integer numberOfRepayments, final Integer repaymentEvery, final BigDecimal interestRatePerPeriod, final Integer repaymentFrequencyType, final Integer interestRateFrequencyType, final Integer amortizationType, final Integer interestType, - final Integer interestCalculationPeriodType) { + final Integer interestCalculationPeriodType, final String[] charges) { this.modifiedParameters = modifiedParameters; this.id = id; this.name = name; @@ -58,6 +60,7 @@ public class LoanProductCommand { this.amortizationType = amortizationType; this.interestType = interestType; this.interestCalculationPeriodType = interestCalculationPeriodType; + this.charges = charges; } public Long getId() { @@ -128,7 +131,11 @@ public class LoanProductCommand { return interestCalculationPeriodType; } - public boolean isNameChanged() { + public String[] getCharges() { + return charges; + } + + public boolean isNameChanged() { return this.modifiedParameters.contains("name"); } @@ -191,4 +198,8 @@ public class LoanProductCommand { public boolean isInterestCalculationPeriodTypeChanged() { return this.modifiedParameters.contains("interestCalculationPeriodType"); } + + public boolean isChargesChanged() { + return this.modifiedParameters.contains("charges"); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ChargeData.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ChargeData.java index f57aff25a..c3dd1df18 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ChargeData.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ChargeData.java @@ -127,4 +127,15 @@ public class ChargeData { public List getChargeTimeTypeOptions() { return chargeTimeTypeOptions; } + + @Override + public boolean equals(Object obj) { + ChargeData chargeData = (ChargeData) obj; + return this.id.equals(chargeData.getId()); + } + + @Override + public int hashCode() { + return this.id.hashCode(); + } } \ No newline at end of file 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 77da2d180..d92786089 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 @@ -36,6 +36,8 @@ public class LoanProductData { private EnumOptionData interestType; private EnumOptionData interestCalculationPeriodType; + private Collection charges; + private DateTime createdOn; private DateTime lastModifedOn; @@ -48,6 +50,7 @@ public class LoanProductData { private List repaymentFrequencyTypeOptions = new ArrayList(); private List interestRateFrequencyTypeOptions = new ArrayList(); private List loanTermFrequencyTypeOptions = new ArrayList(); + private Collection chargeOptions = new ArrayList(); public LoanProductData() { // @@ -354,4 +357,20 @@ public class LoanProductData { List interestCalculationPeriodTypeOptions) { this.interestCalculationPeriodTypeOptions = interestCalculationPeriodTypeOptions; } + + public Collection getCharges() { + return charges; + } + + public void setCharges(Collection charges) { + this.charges = charges; + } + + public Collection getChargeOptions() { + return chargeOptions; + } + + public void setChargeOptions(Collection chargeOptions) { + this.chargeOptions = chargeOptions; + } } \ 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 04825fa2c..e7ccc29f2 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 @@ -345,13 +345,14 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService { throw new InvalidJsonException(); } - Type typeOfMap = new TypeToken>(){}.getType(); - Map requestMap = gsonConverter.fromJson(json, typeOfMap); + Type typeOfMap = new TypeToken>(){}.getType(); + Map requestMap = gsonConverter.fromJson(json, typeOfMap); Set supportedParams = new HashSet( Arrays.asList("name", "description", "fundId", "transactionProcessingStrategyId", "currencyCode", "digitsAfterDecimal", "principal", "inArrearsTolerance", "interestRatePerPeriod", "repaymentEvery", "numberOfRepayments", - "repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "locale") + "repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", + "charges", "locale") ); checkForUnsupportedParameters(requestMap, supportedParams); @@ -376,10 +377,28 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService { Integer amortizationTypeValue = extractIntegerParameter("amortizationType", requestMap, modifiedParameters); Integer interestTypeValue = extractIntegerParameter("interestType", requestMap, modifiedParameters); Integer interestCalculationPeriodTypeValue = extractIntegerParameter("interestCalculationPeriodType", requestMap, modifiedParameters); - + + // check array + JsonParser parser = new JsonParser(); + + String[] charges = null; + JsonElement element = parser.parse(json); + if (element.isJsonObject()) { + JsonObject object = element.getAsJsonObject(); + if (object.has("charges")) { + modifiedParameters.add("charges"); + JsonArray array = object.get("charges").getAsJsonArray(); + charges = new String[array.size()]; + for (int i=0; i SAVINGS_PRODUCT_DATA_PARAMETERS = new HashSet( Arrays.asList("id", "name", "description", "createdOn", diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/charge/domain/Charge.java b/mifosng-provider/src/main/java/org/mifosng/platform/charge/domain/Charge.java index a542d0227..5249338a0 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/charge/domain/Charge.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/charge/domain/Charge.java @@ -71,6 +71,14 @@ public class Charge extends AbstractAuditableCustom { return amount; } + public String getCurrencyCode() { + return currencyCode; + } + + public boolean isActive() { + return active; + } + public boolean isDeleted() { return deleted; } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/charge/service/ChargeReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/charge/service/ChargeReadPlatformService.java index a9b3c39d4..5d0f0d474 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/charge/service/ChargeReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/charge/service/ChargeReadPlatformService.java @@ -11,4 +11,8 @@ public interface ChargeReadPlatformService { ChargeData retrieveCharge(Long chargeId); ChargeData retrieveNewChargeDetails(); + + Collection retrieveLoanApplicableCharges(); + + Collection retrieveLoanProductCharges(Long loanProductId); } 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 ccf72d1b1..a00aab6b2 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 @@ -93,6 +93,29 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService allowedChargeAppliesToOptions, allowedChargeTimeOptions); } + @Override + public Collection retrieveLoanProductCharges(Long loanProductId) { + + this.context.authenticatedUser(); + + ChargeMapper rm = new ChargeMapper(); + + String sql = "select " + rm.loanProductChargeSchema() + " where c.is_deleted=0 and plc.product_loan_id=?"; + + return this.jdbcTemplate.query(sql, rm, new Object[] {loanProductId}); + } + + @Override + public Collection retrieveLoanApplicableCharges() { + this.context.authenticatedUser(); + + 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 "; + + return this.jdbcTemplate.query(sql, rm, new Object[] {ChargeAppliesTo.LOAN.getValue()}); + } + private static final class ChargeMapper implements RowMapper { public String chargeSchema(){ @@ -104,6 +127,10 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService "join m_organisation_currency oc on c.currency_code = oc.code"; } + public String loanProductChargeSchema(){ + return chargeSchema() + " join m_product_loan_charge plc on plc.charge_id = c.id"; + } + @Override public ChargeData mapRow(ResultSet rs, int rowNum) throws SQLException { Long id = rs.getLong("id"); 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 new file mode 100644 index 000000000..f2f6d7605 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/ChargeIsNotActiveException.java @@ -0,0 +1,12 @@ +package org.mifosng.platform.exceptions; + +/** + * {@link AbstractPlatformDomainRuleException} thrown when charge is not active + */ +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); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/InvalidCurrencyException.java b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/InvalidCurrencyException.java new file mode 100644 index 000000000..748c644e2 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/InvalidCurrencyException.java @@ -0,0 +1,12 @@ +package org.mifosng.platform.exceptions; + +/** + * {@link AbstractPlatformDomainRuleException} thrown when currency mismatch occurs + */ +public class InvalidCurrencyException extends AbstractPlatformDomainRuleException { + + public InvalidCurrencyException(final String entity, final String postFix, String defaultUserMessage, Object... defaultUserMessageArgs) { + super("error.msg."+entity+"."+postFix+".invalid.currency", defaultUserMessage, defaultUserMessageArgs); + } + +} 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 42b415653..15540038a 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 @@ -1,16 +1,20 @@ package org.mifosng.platform.loan.domain; import java.math.BigDecimal; +import java.util.Set; import javax.persistence.Column; import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.Table; import org.apache.commons.lang.StringUtils; import org.mifosng.platform.api.commands.LoanProductCommand; +import org.mifosng.platform.charge.domain.Charge; import org.mifosng.platform.currency.domain.MonetaryCurrency; import org.mifosng.platform.currency.domain.Money; import org.mifosng.platform.fund.domain.Fund; @@ -43,6 +47,12 @@ public class LoanProduct extends AbstractAuditableCustom { @Column(name = "description") private String description; + @ManyToMany + @JoinTable(name = "m_product_loan_charge", + joinColumns = @JoinColumn(name = "product_loan_id"), + inverseJoinColumns = @JoinColumn(name = "charge_id")) + private Set charges; + @Embedded private final LoanProductRelatedDetail loanProductRelatedDetail; @@ -58,7 +68,7 @@ public class LoanProduct extends AbstractAuditableCustom { 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) { + final BigDecimal inArrearsTolerance, final Set charges) { this.fund = fund; this.transactionProcessingStrategy = transactionProcessingStrategy; this.name = name.trim(); @@ -67,7 +77,11 @@ public class LoanProduct extends AbstractAuditableCustom { } else { this.description = null; } - + + if (charges != null){ + this.charges = charges; + } + this.loanProductRelatedDetail = new LoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, @@ -138,7 +152,8 @@ public class LoanProduct extends AbstractAuditableCustom { return transactionProcessingStrategy; } - public void update(final LoanProductCommand command, final Fund fund, final LoanTransactionProcessingStrategy strategy) { + public void update(final LoanProductCommand command, final Fund fund, final LoanTransactionProcessingStrategy strategy, + final Set charges) { if (command.isNameChanged()) { this.name = command.getName(); @@ -155,7 +170,11 @@ public class LoanProduct extends AbstractAuditableCustom { if (command.isTransactionProcessingStrategyChanged()) { this.transactionProcessingStrategy = strategy; } - + + if (command.isChargesChanged()){ + this.charges = charges; + } + this.loanProductRelatedDetail.update(command); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductCommandValidator.java b/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductCommandValidator.java index 10bb1d329..18b0d92b5 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductCommandValidator.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductCommandValidator.java @@ -45,7 +45,7 @@ public class LoanProductCommandValidator { baseDataValidator.reset().anyOfNotNull(command.getFundId(), command.getTransactionProcessingStrategyId(), command.getName(), command.getDescription(), command.getCurrencyCode(), command.getDigitsAfterDecimal(), command.getPrincipal(), command.getInArrearsTolerance(), command.getRepaymentFrequencyType(), command.getRepaymentEvery(), command.getNumberOfRepayments(), - command.getInterestRatePerPeriod(), command.getInterestRateFrequencyType(), command.getAmortizationType(), command.getInterestType(), command.getInterestCalculationPeriodType()); + command.getInterestRatePerPeriod(), command.getInterestRateFrequencyType(), command.getAmortizationType(), command.getInterestType(), command.getInterestCalculationPeriodType(), command.getCharges()); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); 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 8fe949f40..f46945bc2 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 @@ -7,6 +7,7 @@ import java.util.Collection; import java.util.List; import org.joda.time.DateTime; +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.FundData; @@ -14,6 +15,7 @@ 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.charge.service.ChargeReadPlatformService; import org.mifosng.platform.currency.service.CurrencyReadPlatformService; import org.mifosng.platform.exceptions.LoanProductNotFoundException; import org.mifosng.platform.fund.service.FundReadPlatformService; @@ -38,6 +40,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo private final JdbcTemplate jdbcTemplate; private final LoanDropdownReadPlatformService dropdownReadPlatformService; private final FundReadPlatformService fundReadPlatformService; + private final ChargeReadPlatformService chargeReadPlatformService; @Autowired public LoanProductReadPlatformServiceImpl( @@ -45,11 +48,13 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo final CurrencyReadPlatformService currencyReadPlatformService, final FundReadPlatformService fundReadPlatformService, final LoanDropdownReadPlatformService dropdownReadPlatformService, + final ChargeReadPlatformService chargeReadPlatformService, final TenantAwareRoutingDataSource dataSource) { this.context = context; this.currencyReadPlatformService = currencyReadPlatformService; this.fundReadPlatformService = fundReadPlatformService; this.dropdownReadPlatformService = dropdownReadPlatformService; + this.chargeReadPlatformService = chargeReadPlatformService; this.jdbcTemplate = new JdbcTemplate(dataSource); } @@ -64,6 +69,9 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo LoanProductData productData = this.jdbcTemplate.queryForObject(sql, rm, new Object[] { loanProductId }); + Collection charges = this.chargeReadPlatformService.retrieveLoanProductCharges(loanProductId); + productData.setCharges(charges); + populateProductDataWithDropdownOptions(productData); return productData; @@ -81,7 +89,13 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo String sql = "select " + rm.loanProductSchema(); - return this.jdbcTemplate.query(sql, rm, new Object[] {}); + Collection loanProducts = this.jdbcTemplate.query(sql, rm, new Object[] {}); + for (LoanProductData loanProduct : loanProducts){ + Collection charges = this.chargeReadPlatformService.retrieveLoanProductCharges(loanProduct.getId()); + loanProduct.setCharges(charges); + } + + return loanProducts; } @Override @@ -112,6 +126,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo productData.setInterestCalculationPeriodType(LoanEnumerations.interestCalculationPeriodType(InterestCalculationPeriodMethod.SAME_AS_REPAYMENT_PERIOD)); + productData.setChargeOptions(this.chargeReadPlatformService.retrieveLoanApplicableCharges()); + populateProductDataWithDropdownOptions(productData); productData.setPrincipal(BigDecimal.ZERO); 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 6a7707661..2eabe1bd5 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 @@ -1,11 +1,18 @@ package org.mifosng.platform.loanproduct.service; import java.math.BigDecimal; +import java.util.HashSet; +import java.util.Set; import org.mifosng.platform.api.commands.LoanProductCommand; import org.mifosng.platform.api.data.EntityIdentifier; +import org.mifosng.platform.charge.domain.Charge; +import org.mifosng.platform.charge.domain.ChargeRepository; import org.mifosng.platform.currency.domain.MonetaryCurrency; +import org.mifosng.platform.exceptions.ChargeIsNotActiveException; +import org.mifosng.platform.exceptions.ChargeNotFoundException; import org.mifosng.platform.exceptions.FundNotFoundException; +import org.mifosng.platform.exceptions.InvalidCurrencyException; import org.mifosng.platform.exceptions.LoanProductNotFoundException; import org.mifosng.platform.exceptions.LoanTransactionProcessingStrategyNotFoundException; import org.mifosng.platform.fund.domain.Fund; @@ -23,6 +30,7 @@ import org.mifosng.platform.security.PlatformSecurityContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.ObjectUtils; @Service public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanProductWritePlatformService { @@ -32,15 +40,18 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro private final AprCalculator aprCalculator; private final FundRepository fundRepository; private final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository; + private final ChargeRepository chargeRepository; @Autowired public LoanProductWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final LoanProductRepository loanProductRepository, - final AprCalculator aprCalculator, final FundRepository fundRepository, final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository) { + final AprCalculator aprCalculator, final FundRepository fundRepository, final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository, + final ChargeRepository chargeRepository) { this.context = context; this.loanProductRepository = loanProductRepository; this.aprCalculator = aprCalculator; this.fundRepository = fundRepository; this.loanTransactionProcessingStrategyRepository = loanTransactionProcessingStrategyRepository; + this.chargeRepository = chargeRepository; } @Transactional @@ -71,13 +82,15 @@ 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()); - + + final Set charges = this.assembleSetOfCharges(command, null); + LoanProduct loanproduct = new LoanProduct(fund, loanTransactionProcessingStrategy, command.getName(), command.getDescription(), currency, command.getPrincipal(), command.getInterestRatePerPeriod(), interestFrequencyType, annualInterestRate, interestMethod, interestCalculationPeriodMethod, command.getRepaymentEvery(), repaymentFrequencyType, command.getNumberOfRepayments(), - amortizationMethod, command.getInArrearsTolerance()); + amortizationMethod, command.getInArrearsTolerance(), charges); this.loanProductRepository.save(loanproduct); @@ -130,11 +143,45 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro if (command.isTransactionProcessingStrategyChanged()) { findStrategyByIdIfProvided(command.getTransactionProcessingStrategyId()); } - - product.update(command, fund, loanTransactionProcessingStrategy); + + final Set charges = this.assembleSetOfCharges(command, product.getCurrency().getCode()); + + product.update(command, fund, loanTransactionProcessingStrategy, charges); this.loanProductRepository.save(product); return new EntityIdentifier(Long.valueOf(product.getId())); } + + private Set assembleSetOfCharges(final LoanProductCommand command, final String currencyCode) { + + Set charges = new HashSet(); + String[] chargesArray = command.getCharges(); + + String loanProductCurrencyCode = command.getCurrencyCode(); + if (loanProductCurrencyCode == null){ + loanProductCurrencyCode = currencyCode; + } + + if (command.isChargesChanged() && !ObjectUtils.isEmpty(chargesArray)) { + for (String chargeId : chargesArray) { + Long id = Long.valueOf(chargeId); + Charge charge = this.chargeRepository.findOne(id); + if (charge == null || charge.isDeleted()) { + throw new ChargeNotFoundException(id); + } + if (!charge.isActive()){ + throw new ChargeIsNotActiveException(id); + } + if (!loanProductCurrencyCode.equals(charge.getCurrencyCode())){ + String errorMessage = "Charge and Loan Product must have the same currency."; + throw new InvalidCurrencyException("charge", "attach.to.loan.product", errorMessage); + } + charges.add(charge); + } + } + + return charges; + } + } \ No newline at end of file