MIFOSX-42 Attach charges to loan products.

This commit is contained in:
Michal Dudzinski
2012-08-30 17:12:25 +02:00
parent 57b38e463a
commit f9d41aa500
15 changed files with 240 additions and 25 deletions
@@ -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<String> 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<String> 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<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges();
chargeOptions.removeAll(loanProduct.getCharges());
loanProduct.setChargeOptions(chargeOptions);
}
return this.apiJsonSerializerService.serializeLoanProductDataToJson(prettyPrint, responseParameters, loanProduct);
@@ -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<String> modifiedParameters;
public LoanProductCommand(final Set<String> 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");
}
}
@@ -127,4 +127,15 @@ public class ChargeData {
public List<EnumOptionData> 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();
}
}
@@ -36,6 +36,8 @@ public class LoanProductData {
private EnumOptionData interestType;
private EnumOptionData interestCalculationPeriodType;
private Collection<ChargeData> charges;
private DateTime createdOn;
private DateTime lastModifedOn;
@@ -48,6 +50,7 @@ public class LoanProductData {
private List<EnumOptionData> repaymentFrequencyTypeOptions = new ArrayList<EnumOptionData>();
private List<EnumOptionData> interestRateFrequencyTypeOptions = new ArrayList<EnumOptionData>();
private List<EnumOptionData> loanTermFrequencyTypeOptions = new ArrayList<EnumOptionData>();
private Collection<ChargeData> chargeOptions = new ArrayList<ChargeData>();
public LoanProductData() {
//
@@ -354,4 +357,20 @@ public class LoanProductData {
List<EnumOptionData> interestCalculationPeriodTypeOptions) {
this.interestCalculationPeriodTypeOptions = interestCalculationPeriodTypeOptions;
}
public Collection<ChargeData> getCharges() {
return charges;
}
public void setCharges(Collection<ChargeData> charges) {
this.charges = charges;
}
public Collection<ChargeData> getChargeOptions() {
return chargeOptions;
}
public void setChargeOptions(Collection<ChargeData> chargeOptions) {
this.chargeOptions = chargeOptions;
}
}
@@ -345,13 +345,14 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
throw new InvalidJsonException();
}
Type typeOfMap = new TypeToken<Map<String, String>>(){}.getType();
Map<String, String> requestMap = gsonConverter.fromJson(json, typeOfMap);
Type typeOfMap = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> requestMap = gsonConverter.fromJson(json, typeOfMap);
Set<String> supportedParams = new HashSet<String>(
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<array.size(); i++) {
charges[i] = array.get(i).getAsString();
}
}
}
//
return new LoanProductCommand(modifiedParameters, resourceIdentifier, name, description, fundId, transactionProcessingStrategyId,
currencyCode, digitsAfterDecimalValue, principalValue, inArrearsToleranceValue, numberOfRepaymentsValue, repaymentEveryValue, interestRatePerPeriodValue,
repaymentFrequencyTypeValue, interestRateFrequencyTypeValue, amortizationTypeValue, interestTypeValue, interestCalculationPeriodTypeValue);
repaymentFrequencyTypeValue, interestRateFrequencyTypeValue, amortizationTypeValue, interestTypeValue, interestCalculationPeriodTypeValue, charges);
}
@Override
@@ -72,12 +72,13 @@ public class GoogleGsonApiJsonSerializerService implements
"annualInterestRate", "repaymentFrequencyType",
"interestRateFrequencyType", "amortizationType",
"interestType", "interestCalculationPeriodType",
"charges",
"createdOn", "lastModifedOn", "currencyOptions",
"amortizationTypeOptions", "interestTypeOptions",
"interestCalculationPeriodTypeOptions",
"repaymentFrequencyTypeOptions",
"interestRateFrequencyTypeOptions", "fundOptions",
"transactionProcessingStrategyOptions"));
"transactionProcessingStrategyOptions", "chargeOptions"));
private static final Set<String> SAVINGS_PRODUCT_DATA_PARAMETERS = new HashSet<String>(
Arrays.asList("id", "name", "description", "createdOn",
@@ -71,6 +71,14 @@ public class Charge extends AbstractAuditableCustom<AppUser, Long> {
return amount;
}
public String getCurrencyCode() {
return currencyCode;
}
public boolean isActive() {
return active;
}
public boolean isDeleted() {
return deleted;
}
@@ -11,4 +11,8 @@ public interface ChargeReadPlatformService {
ChargeData retrieveCharge(Long chargeId);
ChargeData retrieveNewChargeDetails();
Collection<ChargeData> retrieveLoanApplicableCharges();
Collection<ChargeData> retrieveLoanProductCharges(Long loanProductId);
}
@@ -93,6 +93,29 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
allowedChargeAppliesToOptions, allowedChargeTimeOptions);
}
@Override
public Collection<ChargeData> 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<ChargeData> 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<ChargeData> {
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");
@@ -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);
}
}
@@ -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);
}
}
@@ -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<AppUser, Long> {
@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<Charge> charges;
@Embedded
private final LoanProductRelatedDetail loanProductRelatedDetail;
@@ -58,7 +68,7 @@ public class LoanProduct extends AbstractAuditableCustom<AppUser, Long> {
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<Charge> charges) {
this.fund = fund;
this.transactionProcessingStrategy = transactionProcessingStrategy;
this.name = name.trim();
@@ -67,7 +77,11 @@ public class LoanProduct extends AbstractAuditableCustom<AppUser, Long> {
} 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<AppUser, Long> {
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<Charge> charges) {
if (command.isNameChanged()) {
this.name = command.getName();
@@ -155,7 +170,11 @@ public class LoanProduct extends AbstractAuditableCustom<AppUser, Long> {
if (command.isTransactionProcessingStrategyChanged()) {
this.transactionProcessingStrategy = strategy;
}
if (command.isChargesChanged()){
this.charges = charges;
}
this.loanProductRelatedDetail.update(command);
}
}
@@ -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);
@@ -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<ChargeData> 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<LoanProductData> loanProducts = this.jdbcTemplate.query(sql, rm, new Object[] {});
for (LoanProductData loanProduct : loanProducts){
Collection<ChargeData> 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);
@@ -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<Charge> 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<Charge> 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<Charge> assembleSetOfCharges(final LoanProductCommand command, final String currencyCode) {
Set<Charge> charges = new HashSet<Charge>();
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;
}
}