MIFOSX-232: WIP - split out terms and settings related fields on loan product along with charges and accounting related inputs.
This commit is contained in:
+16
-2
@@ -17,6 +17,7 @@ import org.mifosplatform.infrastructure.security.domain.BasicPasswordEncodablePl
|
||||
import org.mifosplatform.infrastructure.security.domain.PlatformUser;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformPasswordEncoder;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
/**
|
||||
@@ -39,8 +40,8 @@ public final class JsonCommand {
|
||||
private final Long apptableId;
|
||||
private final Long datatableId;
|
||||
private final Long codeId;
|
||||
private String supportedEntityType;
|
||||
private Long supportedEntityId;
|
||||
private final String supportedEntityType;
|
||||
private final Long supportedEntityId;
|
||||
private final String transactionId;
|
||||
|
||||
public static JsonCommand from(final String jsonCommand, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper,
|
||||
@@ -86,6 +87,15 @@ public final class JsonCommand {
|
||||
return this.parsedCommand;
|
||||
}
|
||||
|
||||
public String jsonFragment(final String paramName) {
|
||||
String jsonFragment = null;
|
||||
if (this.parsedCommand.getAsJsonObject().has(paramName)) {
|
||||
JsonElement fragment = this.parsedCommand.getAsJsonObject().get(paramName);
|
||||
jsonFragment = this.fromApiJsonHelper.toJson(fragment);
|
||||
}
|
||||
return jsonFragment;
|
||||
}
|
||||
|
||||
public Long commandId() {
|
||||
return this.commandId;
|
||||
}
|
||||
@@ -347,6 +357,10 @@ public final class JsonCommand {
|
||||
return this.fromApiJsonHelper.extractArrayNamed(parameterName, parsedCommand);
|
||||
}
|
||||
|
||||
public JsonArray arrayOfParameterNamed(final String parameterName) {
|
||||
return this.fromApiJsonHelper.extractJsonArrayNamed(parameterName, parsedCommand);
|
||||
}
|
||||
|
||||
public boolean isChangeInPasswordParameterNamed(final String parameterName, final String existingValue,
|
||||
final PlatformPasswordEncoder platformPasswordEncoder, final Long saltValue) {
|
||||
boolean isChanged = false;
|
||||
|
||||
+7
-2
@@ -21,6 +21,7 @@ import org.mifosplatform.infrastructure.core.exception.UnsupportedParameterExcep
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
@@ -46,7 +47,7 @@ public class FromJsonHelper {
|
||||
return this.gsonConverter.fromJson(json, typeOfMap);
|
||||
}
|
||||
|
||||
public <T> T fromJson(final String json, Class<T> classOfT) {
|
||||
public <T> T fromJson(final String json, final Class<T> classOfT) {
|
||||
return this.gsonConverter.fromJson(json, classOfT);
|
||||
}
|
||||
|
||||
@@ -93,6 +94,10 @@ public class FromJsonHelper {
|
||||
return helperDelegator.extractLongNamed(parameterName, element, parametersPassedInRequest);
|
||||
}
|
||||
|
||||
public JsonArray extractJsonArrayNamed(final String parameterName, final JsonElement element) {
|
||||
return helperDelegator.extractJsonArrayNamed(parameterName, element);
|
||||
}
|
||||
|
||||
public String[] extractArrayNamed(final String parameterName, final JsonElement element) {
|
||||
return helperDelegator.extractArrayNamed(parameterName, element, new HashSet<String>());
|
||||
}
|
||||
@@ -109,7 +114,7 @@ public class FromJsonHelper {
|
||||
return helperDelegator.extractBooleanNamed(parameterName, element, parametersPassedInRequest);
|
||||
}
|
||||
|
||||
public LocalDate extractLocalDateNamed(final String parameterName, JsonElement element) {
|
||||
public LocalDate extractLocalDateNamed(final String parameterName, final JsonElement element) {
|
||||
return helperDelegator.extractLocalDateNamed(parameterName, element, new HashSet<String>());
|
||||
}
|
||||
|
||||
|
||||
+24
-10
@@ -32,7 +32,7 @@ import com.google.gson.JsonPrimitive;
|
||||
* Helper class to extract values of json named attributes.
|
||||
*/
|
||||
public class JsonParserHelper {
|
||||
|
||||
|
||||
public boolean parameterExists(final String parameterName, final JsonElement element) {
|
||||
return element.getAsJsonObject().has(parameterName);
|
||||
}
|
||||
@@ -137,19 +137,21 @@ public class JsonParserHelper {
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/** Method used to extract integers from unformatted strings.
|
||||
* Ex: "1" , "100002" etc
|
||||
|
||||
/**
|
||||
* Method used to extract integers from unformatted strings. Ex: "1" ,
|
||||
* "100002" etc
|
||||
*
|
||||
* Please note that this method does not support extracting Integers from locale
|
||||
* specific formatted strings Ex "1,000" etc
|
||||
* Please note that this method does not support extracting Integers from
|
||||
* locale specific formatted strings Ex "1,000" etc
|
||||
*
|
||||
* @param parameterName
|
||||
* @param element
|
||||
* @param parametersPassedInRequest
|
||||
* @return
|
||||
*/
|
||||
public Integer extractIntegerSansLocaleNamed(final String parameterName, final JsonElement element, final Set<String> parametersPassedInRequest) {
|
||||
public Integer extractIntegerSansLocaleNamed(final String parameterName, final JsonElement element,
|
||||
final Set<String> parametersPassedInRequest) {
|
||||
Integer intValue = null;
|
||||
if (element.isJsonObject()) {
|
||||
JsonObject object = element.getAsJsonObject();
|
||||
@@ -211,6 +213,19 @@ public class JsonParserHelper {
|
||||
return arrayValue;
|
||||
}
|
||||
|
||||
public JsonArray extractJsonArrayNamed(final String parameterName, final JsonElement element) {
|
||||
JsonArray jsonArray = null;
|
||||
|
||||
if (element.isJsonObject()) {
|
||||
JsonObject object = element.getAsJsonObject();
|
||||
if (object.has(parameterName)) {
|
||||
jsonArray = object.get(parameterName).getAsJsonArray();
|
||||
}
|
||||
}
|
||||
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used with the local date is in array format
|
||||
*/
|
||||
@@ -391,8 +406,8 @@ public class JsonParserHelper {
|
||||
} catch (NumberFormatException e) {
|
||||
|
||||
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.integer", "The parameter "
|
||||
+ parameterName + " has value: " + numericalValueFormatted + " which is invalid integer.", parameterName, numericalValueFormatted);
|
||||
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.integer", "The parameter " + parameterName
|
||||
+ " has value: " + numericalValueFormatted + " which is invalid integer.", parameterName, numericalValueFormatted);
|
||||
dataValidationErrors.add(error);
|
||||
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
@@ -400,7 +415,6 @@ public class JsonParserHelper {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public BigDecimal convertFrom(final String numericalValueFormatted, final String parameterName, final Locale clientApplicationLocale) {
|
||||
|
||||
if (clientApplicationLocale == null) {
|
||||
|
||||
+15
-30
@@ -11,11 +11,12 @@ import java.util.List;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
|
||||
|
||||
/**
|
||||
* Immutable data object for charge data.
|
||||
*/
|
||||
public class ChargeData {
|
||||
public class ChargeData implements Comparable<ChargeData> {
|
||||
|
||||
private final Long id;
|
||||
private final String name;
|
||||
@@ -72,36 +73,8 @@ public class ChargeData {
|
||||
this.chargeTimeTypeOptions = chargeTimeTypeOptions;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isPenalty() {
|
||||
return this.penalty;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public CurrencyData getCurrency() {
|
||||
return currency;
|
||||
}
|
||||
|
||||
public EnumOptionData getChargeTimeType() {
|
||||
return chargeTimeType;
|
||||
}
|
||||
|
||||
public EnumOptionData getChargeCalculationType() {
|
||||
return chargeCalculationType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(final Object obj) {
|
||||
ChargeData chargeData = (ChargeData) obj;
|
||||
return this.id.equals(chargeData.id);
|
||||
}
|
||||
@@ -110,4 +83,16 @@ public class ChargeData {
|
||||
public int hashCode() {
|
||||
return this.id.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final ChargeData obj) {
|
||||
if (obj == null) { return -1; }
|
||||
|
||||
return obj.id.compareTo(this.id);
|
||||
}
|
||||
|
||||
public LoanChargeData toLoanChargeData() {
|
||||
return LoanChargeData.newLoanChargeDetails(this.id, this.name, this.currency, this.amount, this.chargeTimeType,
|
||||
this.chargeCalculationType, this.penalty);
|
||||
}
|
||||
}
|
||||
+40
-3
@@ -14,8 +14,15 @@ import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
||||
import org.mifosplatform.portfolio.charge.exception.ChargeDueAtDisbursementCannotBePenaltyException;
|
||||
import org.mifosplatform.portfolio.charge.service.ChargeEnumerations;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@Entity
|
||||
@@ -71,7 +78,7 @@ public class Charge extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
private Charge(final String name, final BigDecimal amount, final String currencyCode, final ChargeAppliesTo chargeAppliesTo,
|
||||
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculationType, final boolean penalty, boolean active) {
|
||||
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculationType, final boolean penalty, final boolean active) {
|
||||
this.name = name;
|
||||
this.amount = amount;
|
||||
this.currencyCode = currencyCode;
|
||||
@@ -83,6 +90,24 @@ public class Charge extends AbstractPersistable<Long> {
|
||||
if (penalty && chargeTime.isTimeOfDisbursement()) { throw new ChargeDueAtDisbursementCannotBePenaltyException(name); }
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == null) { return false; }
|
||||
if (obj == this) { return true; }
|
||||
if (obj.getClass() != getClass()) { return false; }
|
||||
LoanCharge rhs = (LoanCharge) obj;
|
||||
return new EqualsBuilder().appendSuper(super.equals(obj)) //
|
||||
.append(this.getId(), rhs.getId()) //
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(3, 5) //
|
||||
.append(this.getId()) //
|
||||
.toHashCode();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -180,8 +205,9 @@ public class Charge extends AbstractPersistable<Long> {
|
||||
actualChanges.put(activeParamName, newValue);
|
||||
this.active = newValue;
|
||||
}
|
||||
|
||||
if (this.penalty && ChargeTimeType.fromInt(this.chargeTime).isTimeOfDisbursement()) { throw new ChargeDueAtDisbursementCannotBePenaltyException(name); }
|
||||
|
||||
if (this.penalty && ChargeTimeType.fromInt(this.chargeTime).isTimeOfDisbursement()) { throw new ChargeDueAtDisbursementCannotBePenaltyException(
|
||||
name); }
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
@@ -196,4 +222,15 @@ public class Charge extends AbstractPersistable<Long> {
|
||||
this.deleted = true;
|
||||
this.name = this.getId() + "_" + this.name;
|
||||
}
|
||||
|
||||
public ChargeData toData() {
|
||||
|
||||
EnumOptionData chargeTimeType = ChargeEnumerations.chargeTimeType(this.chargeTime);
|
||||
EnumOptionData chargeAppliesTo = ChargeEnumerations.chargeAppliesTo(this.chargeAppliesTo);
|
||||
EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(this.chargeCalculation);
|
||||
|
||||
CurrencyData currency = new CurrencyData(this.currencyCode, null, 0, null, null);
|
||||
return ChargeData.instance(this.getId(), this.name, this.amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType,
|
||||
penalty, active);
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -353,8 +353,7 @@ public class LoanAccountData {
|
||||
|
||||
final Collection<LoanChargeData> charges = new ArrayList<LoanChargeData>();
|
||||
for (ChargeData charge : product.charges()) {
|
||||
charges.add(LoanChargeData.newLoanChargeDetails(charge.getId(), charge.getName(), charge.getCurrency(), charge.getAmount(),
|
||||
charge.getChargeTimeType(), charge.getChargeCalculationType(), charge.isPenalty()));
|
||||
charges.add(charge.toLoanChargeData());
|
||||
}
|
||||
|
||||
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
||||
|
||||
+16
-16
@@ -57,12 +57,13 @@ import org.springframework.stereotype.Component;
|
||||
public class LoanProductsApiResource {
|
||||
|
||||
private final Set<String> LOAN_PRODUCT_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "name", "description", "fundId",
|
||||
"fundName", "transactionProcessingStrategyId", "transactionProcessingStrategyName", "principal", "inArrearsTolerance",
|
||||
"numberOfRepayments", "repaymentEvery", "interestRatePerPeriod", "annualInterestRate", "repaymentFrequencyType",
|
||||
"interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "charges", "createdOn",
|
||||
"lastModifedOn", "currencyOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions",
|
||||
"repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "transactionProcessingStrategyOptions",
|
||||
"chargeOptions", "accountingOptions", "accountingRule","accountingRuleOptions","accountingMappings","accountingMappingOptions"));
|
||||
"fundName", "currency", "principal", "numberOfRepayments", "repaymentEvery", "repaymentFrequencyType", "interestRatePerPeriod",
|
||||
"interestRateFrequencyType", "annualInterestRate", "amortizationType", "interestType", "interestCalculationPeriodType",
|
||||
"inArrearsTolerance", "transactionProcessingStrategyId", "transactionProcessingStrategyName", "charges", "accountingRule",
|
||||
"accountingMappings", "fundOptions", "currencyOptions", "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions",
|
||||
"amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions",
|
||||
"transactionProcessingStrategyOptions", "chargeOptions", "accountingOptions", "accountingRuleOptions",
|
||||
"accountingMappingOptions"));
|
||||
|
||||
private final String resourceNameForPermissions = "LOANPRODUCT";
|
||||
|
||||
@@ -129,7 +130,7 @@ public class LoanProductsApiResource {
|
||||
@Path("template")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveNewLoanProductDetails(@Context final UriInfo uriInfo) {
|
||||
public String retrieveTemplate(@Context final UriInfo uriInfo) {
|
||||
|
||||
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
|
||||
|
||||
@@ -154,7 +155,8 @@ public class LoanProductsApiResource {
|
||||
|
||||
Map<String, Object> accountingMappings = null;
|
||||
if (loanProduct.hasAccountingEnabled()) {
|
||||
accountingMappings = accountMappingReadPlatformService.fetchAccountMappingDetailsForLoanProduct(productId, loanProduct.accountingRuleType().getId().intValue());
|
||||
accountingMappings = accountMappingReadPlatformService.fetchAccountMappingDetailsForLoanProduct(productId, loanProduct
|
||||
.accountingRuleType().getId().intValue());
|
||||
loanProduct = LoanProductData.withAccountingMappings(loanProduct, accountingMappings);
|
||||
}
|
||||
|
||||
@@ -182,7 +184,6 @@ public class LoanProductsApiResource {
|
||||
|
||||
final boolean feeChargesOnly = true;
|
||||
Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
|
||||
chargeOptions.removeAll(productData.charges());
|
||||
if (chargeOptions.isEmpty()) {
|
||||
chargeOptions = null;
|
||||
}
|
||||
@@ -192,7 +193,6 @@ public class LoanProductsApiResource {
|
||||
final List<EnumOptionData> interestTypeOptions = dropdownReadPlatformService.retrieveLoanInterestTypeOptions();
|
||||
final List<EnumOptionData> interestCalculationPeriodTypeOptions = dropdownReadPlatformService
|
||||
.retrieveLoanInterestRateCalculatedInPeriodOptions();
|
||||
final List<EnumOptionData> loanTermFrequencyTypeOptions = dropdownReadPlatformService.retrieveLoanTermFrequencyTypeOptions();
|
||||
final List<EnumOptionData> repaymentFrequencyTypeOptions = dropdownReadPlatformService.retrieveRepaymentFrequencyTypeOptions();
|
||||
final List<EnumOptionData> interestRateFrequencyTypeOptions = dropdownReadPlatformService
|
||||
.retrieveInterestRateFrequencyTypeOptions();
|
||||
@@ -204,29 +204,29 @@ public class LoanProductsApiResource {
|
||||
final Collection<TransactionProcessingStrategyData> transactionProcessingStrategyOptions = this.dropdownReadPlatformService
|
||||
.retreiveTransactionProcessingStrategies();
|
||||
|
||||
Map<String, List<GLAccountData>> accountOptions= new HashMap<String, List<GLAccountData>>();
|
||||
Map<String, List<GLAccountData>> accountOptions = new HashMap<String, List<GLAccountData>>();
|
||||
List<GLAccountData> assetAccountOptions = accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.ASSET);
|
||||
if (assetAccountOptions.isEmpty()) {
|
||||
assetAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("assetAccountOptions", assetAccountOptions);
|
||||
|
||||
|
||||
List<GLAccountData> incomeAccountOptions = accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.INCOME);
|
||||
if (incomeAccountOptions.isEmpty()) {
|
||||
incomeAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("incomeAccountOptions", incomeAccountOptions);
|
||||
|
||||
|
||||
List<GLAccountData> expenseAccountOptions = accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.EXPENSE);
|
||||
if (expenseAccountOptions.isEmpty()) {
|
||||
expenseAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("expenseAccountOptions", expenseAccountOptions);
|
||||
|
||||
|
||||
List<EnumOptionData> accountingRuleTypeOptions = dropdownReadPlatformService.retrieveAccountingRuleTypeOptions();
|
||||
|
||||
return new LoanProductData(productData, chargeOptions, currencyOptions, amortizationTypeOptions, interestTypeOptions,
|
||||
interestCalculationPeriodTypeOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
|
||||
interestRateFrequencyTypeOptions, fundOptions, transactionProcessingStrategyOptions, accountOptions, accountingRuleTypeOptions,accountingMappings);
|
||||
interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions, interestRateFrequencyTypeOptions, fundOptions,
|
||||
transactionProcessingStrategyOptions, accountOptions, accountingRuleTypeOptions, accountingMappings);
|
||||
}
|
||||
}
|
||||
+57
-66
@@ -33,47 +33,46 @@ public class LoanProductData {
|
||||
private final String description;
|
||||
private final Long fundId;
|
||||
private final String fundName;
|
||||
|
||||
// terms
|
||||
private final CurrencyData currency;
|
||||
private final BigDecimal principal;
|
||||
private final Integer numberOfRepayments;
|
||||
private final Integer loanTermFrequency;
|
||||
private final Integer repaymentEvery;
|
||||
private final EnumOptionData loanTermFrequencyType;
|
||||
private final EnumOptionData repaymentFrequencyType;
|
||||
private final Long transactionProcessingStrategyId;
|
||||
private final String transactionProcessingStrategyName;
|
||||
private final BigDecimal interestRatePerPeriod;
|
||||
private final EnumOptionData interestRateFrequencyType;
|
||||
private final BigDecimal annualInterestRate;
|
||||
|
||||
// settings
|
||||
private final EnumOptionData amortizationType;
|
||||
private final EnumOptionData interestType;
|
||||
private final EnumOptionData interestCalculationPeriodType;
|
||||
private final BigDecimal inArrearsTolerance;
|
||||
private final Long transactionProcessingStrategyId;
|
||||
private final String transactionProcessingStrategyName;
|
||||
|
||||
private final EnumOptionData accountingRule;
|
||||
|
||||
// charges
|
||||
private final Collection<ChargeData> charges;
|
||||
|
||||
// accounting
|
||||
private final EnumOptionData accountingRule;
|
||||
@SuppressWarnings("unused")
|
||||
private final Map<String, Object> accountingMappings;
|
||||
|
||||
// template related
|
||||
private final Collection<CurrencyData> currencyOptions;
|
||||
private final Collection<FundData> fundOptions;
|
||||
private final Collection<TransactionProcessingStrategyData> transactionProcessingStrategyOptions;
|
||||
private final Collection<CurrencyData> currencyOptions;
|
||||
private final List<EnumOptionData> repaymentFrequencyTypeOptions;
|
||||
private final List<EnumOptionData> interestRateFrequencyTypeOptions;
|
||||
private final List<EnumOptionData> amortizationTypeOptions;
|
||||
private final List<EnumOptionData> interestTypeOptions;
|
||||
private final List<EnumOptionData> interestCalculationPeriodTypeOptions;
|
||||
private final List<EnumOptionData> repaymentFrequencyTypeOptions;
|
||||
private final List<EnumOptionData> interestRateFrequencyTypeOptions;
|
||||
private final List<EnumOptionData> loanTermFrequencyTypeOptions;
|
||||
private final Collection<TransactionProcessingStrategyData> transactionProcessingStrategyOptions;
|
||||
private final Collection<ChargeData> chargeOptions;
|
||||
|
||||
// accounting related template fields
|
||||
private final List<EnumOptionData> accountingRuleOptions;
|
||||
private final Map<String, List<GLAccountData>> accountingMappingOptions;
|
||||
|
||||
// accounting related mapping fields
|
||||
@SuppressWarnings("unused")
|
||||
private final Map<String, Object> accountingMappings;
|
||||
|
||||
/**
|
||||
* Used when returning lookup information about loan product for dropdowns.
|
||||
*/
|
||||
@@ -83,11 +82,9 @@ public class LoanProductData {
|
||||
final BigDecimal principal = null;
|
||||
final BigDecimal tolerance = null;
|
||||
final Integer numberOfRepayments = null;
|
||||
final Integer loanTermFrequency = null;
|
||||
final Integer repaymentEvery = null;
|
||||
final BigDecimal interestRatePerPeriod = null;
|
||||
final BigDecimal annualInterestRate = null;
|
||||
final EnumOptionData loanTermFrequencyType = null;
|
||||
final EnumOptionData repaymentFrequencyType = null;
|
||||
final EnumOptionData interestRateFrequencyType = null;
|
||||
final EnumOptionData amortizationType = null;
|
||||
@@ -100,10 +97,10 @@ public class LoanProductData {
|
||||
final Collection<ChargeData> charges = null;
|
||||
final EnumOptionData accountingType = null;
|
||||
|
||||
return new LoanProductData(id, name, description, currency, principal, tolerance, numberOfRepayments, loanTermFrequency,
|
||||
repaymentEvery, interestRatePerPeriod, annualInterestRate, loanTermFrequencyType, repaymentFrequencyType,
|
||||
interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, fundId, fundName,
|
||||
transactionProcessingStrategyId, transactionProcessingStrategyName, charges, accountingType);
|
||||
return new LoanProductData(id, name, description, currency, principal, tolerance, numberOfRepayments, repaymentEvery,
|
||||
interestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType,
|
||||
interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId,
|
||||
transactionProcessingStrategyName, charges, accountingType);
|
||||
}
|
||||
|
||||
public static LoanProductData sensibleDefaultsForNewLoanProductCreation() {
|
||||
@@ -114,11 +111,9 @@ public class LoanProductData {
|
||||
final BigDecimal principal = null;
|
||||
final BigDecimal tolerance = null;
|
||||
final Integer numberOfRepayments = null;
|
||||
final Integer loanTermFrequency = null;
|
||||
final Integer repaymentEvery = null;
|
||||
final BigDecimal interestRatePerPeriod = null;
|
||||
final BigDecimal annualInterestRate = null;
|
||||
final EnumOptionData loanTermFrequencyType = LoanEnumerations.loanTermFrequencyType(PeriodFrequencyType.MONTHS);
|
||||
final EnumOptionData repaymentFrequencyType = LoanEnumerations.repaymentFrequencyType(PeriodFrequencyType.MONTHS);
|
||||
final EnumOptionData interestRateFrequencyType = LoanEnumerations.interestRateFrequencyType(PeriodFrequencyType.MONTHS);
|
||||
final EnumOptionData amortizationType = LoanEnumerations.amortizationType(AmortizationMethod.EQUAL_INSTALLMENTS);
|
||||
@@ -132,25 +127,24 @@ public class LoanProductData {
|
||||
final Collection<ChargeData> charges = null;
|
||||
final EnumOptionData accountingType = LoanEnumerations.accountingRuleType(AccountingRuleType.NONE);
|
||||
|
||||
return new LoanProductData(id, name, description, currency, principal, tolerance, numberOfRepayments, loanTermFrequency,
|
||||
repaymentEvery, interestRatePerPeriod, annualInterestRate, loanTermFrequencyType, repaymentFrequencyType,
|
||||
interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, fundId, fundName,
|
||||
transactionProcessingStrategyId, transactionProcessingStrategyName, charges, accountingType);
|
||||
return new LoanProductData(id, name, description, currency, principal, tolerance, numberOfRepayments, repaymentEvery,
|
||||
interestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType,
|
||||
interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId,
|
||||
transactionProcessingStrategyName, charges, accountingType);
|
||||
}
|
||||
|
||||
public static LoanProductData withAccountingMappings(final LoanProductData productData, final Map<String, Object> accountingMappings) {
|
||||
|
||||
return new LoanProductData(productData, productData.chargeOptions, productData.currencyOptions,
|
||||
productData.amortizationTypeOptions, productData.interestTypeOptions, productData.interestCalculationPeriodTypeOptions,
|
||||
productData.loanTermFrequencyTypeOptions, productData.repaymentFrequencyTypeOptions,
|
||||
productData.interestRateFrequencyTypeOptions, productData.fundOptions, productData.transactionProcessingStrategyOptions,
|
||||
productData.accountingMappingOptions, productData.accountingRuleOptions, accountingMappings);
|
||||
productData.repaymentFrequencyTypeOptions, productData.interestRateFrequencyTypeOptions, productData.fundOptions,
|
||||
productData.transactionProcessingStrategyOptions, productData.accountingMappingOptions, productData.accountingRuleOptions,
|
||||
accountingMappings);
|
||||
}
|
||||
|
||||
public LoanProductData(final Long id, final String name, final String description, final CurrencyData currency,
|
||||
final BigDecimal principal, final BigDecimal tolerance, final Integer numberOfRepayments, final Integer loanTermFrequency,
|
||||
final Integer repaymentEvery, final BigDecimal interestRatePerPeriod, final BigDecimal annualInterestRate,
|
||||
final EnumOptionData loanTermFrequencyType, final EnumOptionData repaymentFrequencyType,
|
||||
final BigDecimal principal, final BigDecimal tolerance, final Integer numberOfRepayments, final Integer repaymentEvery,
|
||||
final BigDecimal interestRatePerPeriod, final BigDecimal annualInterestRate, final EnumOptionData repaymentFrequencyType,
|
||||
final EnumOptionData interestRateFrequencyType, final EnumOptionData amortizationType, final EnumOptionData interestType,
|
||||
final EnumOptionData interestCalculationPeriodType, final Long fundId, final String fundName,
|
||||
final Long transactionProcessingStrategyId, final String transactionProcessingStrategyName,
|
||||
@@ -162,11 +156,11 @@ public class LoanProductData {
|
||||
this.principal = principal;
|
||||
this.inArrearsTolerance = tolerance;
|
||||
this.numberOfRepayments = numberOfRepayments;
|
||||
this.loanTermFrequency = loanTermFrequency;
|
||||
// this.loanTermFrequency = loanTermFrequency;
|
||||
this.repaymentEvery = repaymentEvery;
|
||||
this.interestRatePerPeriod = interestRatePerPeriod;
|
||||
this.annualInterestRate = annualInterestRate;
|
||||
this.loanTermFrequencyType = loanTermFrequencyType;
|
||||
// this.loanTermFrequencyType = loanTermFrequencyType;
|
||||
this.repaymentFrequencyType = repaymentFrequencyType;
|
||||
this.interestRateFrequencyType = interestRateFrequencyType;
|
||||
this.amortizationType = amortizationType;
|
||||
@@ -186,7 +180,7 @@ public class LoanProductData {
|
||||
this.amortizationTypeOptions = null;
|
||||
this.interestTypeOptions = null;
|
||||
this.interestCalculationPeriodTypeOptions = null;
|
||||
this.loanTermFrequencyTypeOptions = null;
|
||||
// this.loanTermFrequencyTypeOptions = null;
|
||||
this.repaymentFrequencyTypeOptions = null;
|
||||
this.interestRateFrequencyTypeOptions = null;
|
||||
|
||||
@@ -198,31 +192,29 @@ public class LoanProductData {
|
||||
public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
|
||||
final Collection<CurrencyData> currencyOptions, final List<EnumOptionData> amortizationTypeOptions,
|
||||
final List<EnumOptionData> interestTypeOptions, final List<EnumOptionData> interestCalculationPeriodTypeOptions,
|
||||
final List<EnumOptionData> loanTermFrequencyTypeOptions, final List<EnumOptionData> repaymentFrequencyTypeOptions,
|
||||
final List<EnumOptionData> interestRateFrequencyTypeOptions, final Collection<FundData> fundOptions,
|
||||
final Collection<TransactionProcessingStrategyData> transactionProcessingStrategyOptions,
|
||||
final List<EnumOptionData> repaymentFrequencyTypeOptions, final List<EnumOptionData> interestRateFrequencyTypeOptions,
|
||||
final Collection<FundData> fundOptions,
|
||||
final Collection<TransactionProcessingStrategyData> transactionStrategyOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions, final List<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, Object> accountingMappings) {
|
||||
this.id = productData.id;
|
||||
this.name = productData.name;
|
||||
this.description = productData.description;
|
||||
this.fundId = productData.fundId;
|
||||
this.fundName = productData.fundName;
|
||||
|
||||
this.principal = productData.principal;
|
||||
this.inArrearsTolerance = productData.inArrearsTolerance;
|
||||
this.numberOfRepayments = productData.numberOfRepayments;
|
||||
this.loanTermFrequency = productData.loanTermFrequency;
|
||||
this.repaymentEvery = productData.repaymentEvery;
|
||||
this.interestRatePerPeriod = productData.interestRatePerPeriod;
|
||||
this.annualInterestRate = productData.annualInterestRate;
|
||||
this.loanTermFrequencyType = productData.loanTermFrequencyType;
|
||||
this.repaymentFrequencyType = productData.repaymentFrequencyType;
|
||||
this.interestRateFrequencyType = productData.interestRateFrequencyType;
|
||||
this.amortizationType = productData.amortizationType;
|
||||
this.interestType = productData.interestType;
|
||||
this.interestCalculationPeriodType = productData.interestCalculationPeriodType;
|
||||
this.fundId = productData.fundId;
|
||||
this.fundName = productData.fundName;
|
||||
this.transactionProcessingStrategyId = productData.transactionProcessingStrategyId;
|
||||
this.transactionProcessingStrategyName = productData.transactionProcessingStrategyName;
|
||||
|
||||
this.charges = nullIfEmpty(productData.charges());
|
||||
this.accountingRule = productData.accountingRule;
|
||||
|
||||
@@ -234,17 +226,32 @@ public class LoanProductData {
|
||||
this.currency = productData.currency;
|
||||
}
|
||||
this.fundOptions = fundOptions;
|
||||
this.transactionProcessingStrategyOptions = transactionProcessingStrategyOptions;
|
||||
this.transactionProcessingStrategyOptions = transactionStrategyOptions;
|
||||
if (this.transactionProcessingStrategyOptions != null && this.transactionProcessingStrategyOptions.size() == 1) {
|
||||
final List<TransactionProcessingStrategyData> listOfOptions = new ArrayList<TransactionProcessingStrategyData>(
|
||||
this.transactionProcessingStrategyOptions);
|
||||
|
||||
this.transactionProcessingStrategyId = listOfOptions.get(0).id();
|
||||
this.transactionProcessingStrategyName = listOfOptions.get(0).name();
|
||||
} else {
|
||||
this.transactionProcessingStrategyId = productData.transactionProcessingStrategyId;
|
||||
this.transactionProcessingStrategyName = productData.transactionProcessingStrategyName;
|
||||
}
|
||||
|
||||
this.amortizationTypeOptions = amortizationTypeOptions;
|
||||
this.interestTypeOptions = interestTypeOptions;
|
||||
this.interestCalculationPeriodTypeOptions = interestCalculationPeriodTypeOptions;
|
||||
this.loanTermFrequencyTypeOptions = loanTermFrequencyTypeOptions;
|
||||
this.repaymentFrequencyTypeOptions = repaymentFrequencyTypeOptions;
|
||||
this.interestRateFrequencyTypeOptions = interestRateFrequencyTypeOptions;
|
||||
|
||||
this.accountingMappingOptions = accountingMappingOptions;
|
||||
this.accountingRuleOptions = accountingRuleOptions;
|
||||
this.accountingMappings = accountingMappings;
|
||||
|
||||
if (accountingMappings == null || accountingMappings.isEmpty()) {
|
||||
this.accountingMappings = null;
|
||||
} else {
|
||||
this.accountingMappings = accountingMappings;
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData> charges) {
|
||||
@@ -315,10 +322,6 @@ public class LoanProductData {
|
||||
return numberOfRepayments;
|
||||
}
|
||||
|
||||
public Integer getLoanTermFrequency() {
|
||||
return loanTermFrequency;
|
||||
}
|
||||
|
||||
public Integer getRepaymentEvery() {
|
||||
return repaymentEvery;
|
||||
}
|
||||
@@ -331,10 +334,6 @@ public class LoanProductData {
|
||||
return annualInterestRate;
|
||||
}
|
||||
|
||||
public EnumOptionData getLoanTermFrequencyType() {
|
||||
return loanTermFrequencyType;
|
||||
}
|
||||
|
||||
public EnumOptionData getRepaymentFrequencyType() {
|
||||
return repaymentFrequencyType;
|
||||
}
|
||||
@@ -359,10 +358,6 @@ public class LoanProductData {
|
||||
return fundOptions;
|
||||
}
|
||||
|
||||
public Collection<TransactionProcessingStrategyData> getTransactionProcessingStrategyOptions() {
|
||||
return transactionProcessingStrategyOptions;
|
||||
}
|
||||
|
||||
public List<EnumOptionData> getAmortizationTypeOptions() {
|
||||
return amortizationTypeOptions;
|
||||
}
|
||||
@@ -383,10 +378,6 @@ public class LoanProductData {
|
||||
return interestRateFrequencyTypeOptions;
|
||||
}
|
||||
|
||||
public List<EnumOptionData> getLoanTermFrequencyTypeOptions() {
|
||||
return loanTermFrequencyTypeOptions;
|
||||
}
|
||||
|
||||
public Collection<ChargeData> getChargeOptions() {
|
||||
return chargeOptions;
|
||||
}
|
||||
|
||||
+11
-2
@@ -5,13 +5,14 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.loanproduct.data;
|
||||
|
||||
/**
|
||||
* Immutable data object representing a transaction strategy option for a loan.
|
||||
*/
|
||||
public final class TransactionProcessingStrategyData {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Long id;
|
||||
@SuppressWarnings("unused")
|
||||
private final String code;
|
||||
@SuppressWarnings("unused")
|
||||
private final String name;
|
||||
|
||||
public TransactionProcessingStrategyData(final Long id, final String code, final String name) {
|
||||
@@ -19,4 +20,12 @@ public final class TransactionProcessingStrategyData {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long id() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
+25
-31
@@ -6,7 +6,7 @@
|
||||
package org.mifosplatform.portfolio.loanproduct.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -29,6 +29,8 @@ import org.mifosplatform.portfolio.fund.domain.Fund;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
|
||||
/**
|
||||
* Loan products allow for categorisation of an organisations loans into
|
||||
* something meaningful to them.
|
||||
@@ -39,7 +41,7 @@ import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
* They allow for constraints to be added at product level.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "m_product_loan" , uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "unq_name")})
|
||||
@Table(name = "m_product_loan", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "unq_name") })
|
||||
public class LoanProduct extends AbstractPersistable<Long> {
|
||||
|
||||
@ManyToOne
|
||||
@@ -50,7 +52,7 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
@JoinColumn(name = "loan_transaction_strategy_id", nullable = true)
|
||||
private LoanTransactionProcessingStrategy transactionProcessingStrategy;
|
||||
|
||||
@Column(name = "name", nullable = false , unique = true)
|
||||
@Column(name = "name", nullable = false, unique = true)
|
||||
private String name;
|
||||
|
||||
@Column(name = "description")
|
||||
@@ -58,7 +60,7 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
|
||||
@ManyToMany
|
||||
@JoinTable(name = "m_product_loan_charge", joinColumns = @JoinColumn(name = "product_loan_id"), inverseJoinColumns = @JoinColumn(name = "charge_id"))
|
||||
private Set<Charge> charges;
|
||||
private List<Charge> charges;
|
||||
|
||||
@Embedded
|
||||
private final LoanProductRelatedDetail loanProductRelatedDetail;
|
||||
@@ -67,7 +69,7 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
private Integer accountingRule;
|
||||
|
||||
public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy,
|
||||
final Set<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator) {
|
||||
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator) {
|
||||
|
||||
final String name = command.stringValueOfParameterNamed("name");
|
||||
final String description = command.stringValueOfParameterNamed("description");
|
||||
@@ -108,7 +110,7 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
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 Set<Charge> charges,
|
||||
final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance, final List<Charge> charges,
|
||||
final AccountingRuleType accountingRuleType) {
|
||||
this.fund = fund;
|
||||
this.transactionProcessingStrategy = transactionProcessingStrategy;
|
||||
@@ -136,10 +138,6 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
return this.loanProductRelatedDetail.getCurrency();
|
||||
}
|
||||
|
||||
public Set<Charge> getCharges() {
|
||||
return charges;
|
||||
}
|
||||
|
||||
public void update(final Fund fund) {
|
||||
this.fund = fund;
|
||||
}
|
||||
@@ -148,8 +146,17 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
this.transactionProcessingStrategy = strategy;
|
||||
}
|
||||
|
||||
public void update(final Set<Charge> charges) {
|
||||
this.charges = charges;
|
||||
public boolean update(final List<Charge> newProductCharges) {
|
||||
boolean updated = false;
|
||||
if (this.charges != null) {
|
||||
final Set<Charge> setOfCharges = new HashSet<Charge>(this.charges);
|
||||
|
||||
updated = setOfCharges.addAll(newProductCharges);
|
||||
if (updated) {
|
||||
this.charges = newProductCharges;
|
||||
}
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
public Integer getAccountingType() {
|
||||
@@ -202,30 +209,17 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
final String chargesParamName = "charges";
|
||||
if (command.isChangeInArrayParameterNamed(chargesParamName, getChargesIds())) {
|
||||
final String[] newValue = command.arrayValueOfParameterNamed(chargesParamName);
|
||||
actualChanges.put(chargesParamName, newValue);
|
||||
if (command.hasParameter(chargesParamName)) {
|
||||
JsonArray jsonArray = command.arrayOfParameterNamed(chargesParamName);
|
||||
if (jsonArray != null) {
|
||||
|
||||
}
|
||||
actualChanges.put(chargesParamName, command.jsonFragment(chargesParamName));
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
private String[] getChargesIds() {
|
||||
final List<String> chargeIds = new ArrayList<String>();
|
||||
|
||||
if (this.charges != null) {
|
||||
for (Charge charge : this.charges) {
|
||||
chargeIds.add(charge.getId().toString());
|
||||
}
|
||||
}
|
||||
|
||||
return chargeIds.toArray(new String[chargeIds.size()]);
|
||||
}
|
||||
|
||||
public boolean isAccountingEnabled() {
|
||||
return !AccountingRuleType.NONE.getValue().equals(this.accountingRule);
|
||||
}
|
||||
|
||||
public boolean isCashBasedAccountingEnabled() {
|
||||
return AccountingRuleType.CASH_BASED.getValue().equals(this.accountingRule);
|
||||
}
|
||||
|
||||
+16
-14
@@ -35,10 +35,10 @@ public final class LoanProductCommandFromApiJsonDeserializer {
|
||||
/**
|
||||
* The parameters supported for this command.
|
||||
*/
|
||||
private final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("name", "description", "fundId",
|
||||
"transactionProcessingStrategyId", "currencyCode", "digitsAfterDecimal", "principal", "inArrearsTolerance",
|
||||
"interestRatePerPeriod", "repaymentEvery", "numberOfRepayments", "repaymentFrequencyType", "interestRateFrequencyType",
|
||||
"amortizationType", "interestType", "interestCalculationPeriodType", "charges", "locale", "accountingRule",
|
||||
private final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("locale", "name", "description", "fundId",
|
||||
"currencyCode", "digitsAfterDecimal", "principal", "repaymentEvery", "numberOfRepayments", "repaymentFrequencyType",
|
||||
"interestRatePerPeriod", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType",
|
||||
"inArrearsTolerance", "transactionProcessingStrategyId", "charges", "accountingRule",
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(),
|
||||
@@ -74,6 +74,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
|
||||
baseDataValidator.reset().parameter("fundId").value(fundId).ignoreIfNull().integerGreaterThanZero();
|
||||
}
|
||||
|
||||
// terms
|
||||
final String currencyCode = fromApiJsonHelper.extractStringNamed("currencyCode", element);
|
||||
baseDataValidator.reset().parameter("currencyCode").value(currencyCode).notBlank().notExceedingLengthOf(3);
|
||||
|
||||
@@ -83,12 +84,6 @@ public final class LoanProductCommandFromApiJsonDeserializer {
|
||||
final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element);
|
||||
baseDataValidator.reset().parameter("principal").value(principal).notNull().positiveAmount();
|
||||
|
||||
final BigDecimal inArrearsTolerance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("inArrearsTolerance", element);
|
||||
baseDataValidator.reset().parameter("inArrearsTolerance").value(inArrearsTolerance).ignoreIfNull().zeroOrPositiveAmount();
|
||||
|
||||
final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element);
|
||||
baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod).notNull().zeroOrPositiveAmount();
|
||||
|
||||
final Integer numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed("numberOfRepayments", element);
|
||||
baseDataValidator.reset().parameter("numberOfRepayments").value(numberOfRepayments).notNull().integerGreaterThanZero();
|
||||
|
||||
@@ -99,14 +94,14 @@ public final class LoanProductCommandFromApiJsonDeserializer {
|
||||
.extractIntegerNamed("repaymentFrequencyType", element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter("repaymentFrequencyType").value(repaymentFrequencyType).notNull().inMinMaxRange(0, 3);
|
||||
|
||||
final Long transactionProcessingStrategyId = fromApiJsonHelper.extractLongNamed("transactionProcessingStrategyId", element);
|
||||
baseDataValidator.reset().parameter("transactionProcessingStrategyId").value(transactionProcessingStrategyId).notNull()
|
||||
.integerGreaterThanZero();
|
||||
final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element);
|
||||
baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod).notNull().zeroOrPositiveAmount();
|
||||
|
||||
final Integer interestRateFrequencyType = fromApiJsonHelper.extractIntegerNamed("interestRateFrequencyType", element,
|
||||
Locale.getDefault());
|
||||
baseDataValidator.reset().parameter("interestRateFrequencyType").value(interestRateFrequencyType).notNull().inMinMaxRange(0, 3);
|
||||
|
||||
// settings
|
||||
final Integer amortizationType = fromApiJsonHelper.extractIntegerNamed("amortizationType", element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter("amortizationType").value(amortizationType).notNull().inMinMaxRange(0, 1);
|
||||
|
||||
@@ -118,6 +113,13 @@ public final class LoanProductCommandFromApiJsonDeserializer {
|
||||
baseDataValidator.reset().parameter("interestCalculationPeriodType").value(interestCalculationPeriodType).notNull()
|
||||
.inMinMaxRange(0, 1);
|
||||
|
||||
final BigDecimal inArrearsTolerance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("inArrearsTolerance", element);
|
||||
baseDataValidator.reset().parameter("inArrearsTolerance").value(inArrearsTolerance).ignoreIfNull().zeroOrPositiveAmount();
|
||||
|
||||
final Long transactionProcessingStrategyId = fromApiJsonHelper.extractLongNamed("transactionProcessingStrategyId", element);
|
||||
baseDataValidator.reset().parameter("transactionProcessingStrategyId").value(transactionProcessingStrategyId).notNull()
|
||||
.integerGreaterThanZero();
|
||||
|
||||
// accounting related data validation
|
||||
final Integer accountingRuleType = fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 3);
|
||||
@@ -176,7 +178,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
public void validateForUpdate(String json) {
|
||||
public void validateForUpdate(final String json) {
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
|
||||
+8
-11
@@ -134,19 +134,16 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
|
||||
final Integer numberOfRepayments = JdbcSupport.getInteger(rs, "numberOfRepayments");
|
||||
final Integer repaymentEvery = JdbcSupport.getInteger(rs, "repaidEvery");
|
||||
|
||||
final Integer accountingTypeId = JdbcSupport.getInteger(rs, "accountingType");
|
||||
final EnumOptionData accountingRuleType = LoanEnumerations.accountingRuleType(accountingTypeId);
|
||||
|
||||
final Integer loanTermFrequency = repaymentEvery * numberOfRepayments;
|
||||
|
||||
final Integer accountingRuleId = JdbcSupport.getInteger(rs, "accountingType");
|
||||
final EnumOptionData accountingRuleType = LoanEnumerations.accountingRuleType(accountingRuleId);
|
||||
|
||||
final BigDecimal interestRatePerPeriod = rs.getBigDecimal("interestRatePerPeriod");
|
||||
final BigDecimal annualInterestRate = rs.getBigDecimal("annualInterestRate");
|
||||
|
||||
final int repaymentFrequencyTypeId = JdbcSupport.getInteger(rs, "repaymentPeriodFrequency");
|
||||
final EnumOptionData repaymentFrequencyType = LoanEnumerations.repaymentFrequencyType(repaymentFrequencyTypeId);
|
||||
|
||||
final EnumOptionData loanTermFrequencyType = LoanEnumerations.loanTermFrequencyType(repaymentFrequencyTypeId);
|
||||
|
||||
final int amortizationTypeId = JdbcSupport.getInteger(rs, "amortizationMethod");
|
||||
final EnumOptionData amortizationType = LoanEnumerations.amortizationType(amortizationTypeId);
|
||||
|
||||
@@ -160,10 +157,10 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
final EnumOptionData interestCalculationPeriodType = LoanEnumerations
|
||||
.interestCalculationPeriodType(interestCalculationPeriodTypeId);
|
||||
|
||||
return new LoanProductData(id, name, description, currency, principal, tolerance, numberOfRepayments, loanTermFrequency,
|
||||
repaymentEvery, interestRatePerPeriod, annualInterestRate, loanTermFrequencyType, repaymentFrequencyType,
|
||||
interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, fundId, fundName,
|
||||
transactionStrategyId, transactionStrategyName, this.charges, accountingRuleType);
|
||||
return new LoanProductData(id, name, description, currency, principal, tolerance, numberOfRepayments, repaymentEvery,
|
||||
interestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType,
|
||||
interestType, interestCalculationPeriodType, fundId, fundName, transactionStrategyId, transactionStrategyName,
|
||||
this.charges, accountingRuleType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+39
-33
@@ -5,9 +5,9 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.loanproduct.service;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.service.ProductToGLAccountMappingWritePlatformService;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
@@ -16,9 +16,7 @@ import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.charge.domain.Charge;
|
||||
import org.mifosplatform.portfolio.charge.domain.ChargeRepository;
|
||||
import org.mifosplatform.portfolio.charge.exception.ChargeIsNotActiveException;
|
||||
import org.mifosplatform.portfolio.charge.exception.ChargeNotFoundException;
|
||||
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.fund.domain.Fund;
|
||||
import org.mifosplatform.portfolio.fund.domain.FundRepository;
|
||||
import org.mifosplatform.portfolio.fund.exception.FundNotFoundException;
|
||||
@@ -31,13 +29,15 @@ import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingS
|
||||
import org.mifosplatform.portfolio.loanproduct.exception.InvalidCurrencyException;
|
||||
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
||||
import org.mifosplatform.portfolio.loanproduct.serialization.LoanProductCommandFromApiJsonDeserializer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
@Service
|
||||
public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanProductWritePlatformService {
|
||||
@@ -49,7 +49,7 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
||||
private final AprCalculator aprCalculator;
|
||||
private final FundRepository fundRepository;
|
||||
private final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository;
|
||||
private final ChargeRepository chargeRepository;
|
||||
private final ChargeRepositoryWrapper chargeRepository;
|
||||
private final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
@@ -57,7 +57,8 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
||||
final LoanProductCommandFromApiJsonDeserializer fromApiJsonDeserializer, final LoanProductRepository loanProductRepository,
|
||||
final AprCalculator aprCalculator, final FundRepository fundRepository,
|
||||
final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository,
|
||||
final ChargeRepository chargeRepository, final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService) {
|
||||
final ChargeRepositoryWrapper chargeRepository,
|
||||
final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService) {
|
||||
this.context = context;
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.loanProductRepository = loanProductRepository;
|
||||
@@ -78,15 +79,13 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
||||
|
||||
this.fromApiJsonDeserializer.validateForCreate(command.json());
|
||||
|
||||
// associating fund with loan product at creation is optional for
|
||||
// now.
|
||||
final Fund fund = findFundByIdIfProvided(command.longValueOfParameterNamed("fundId"));
|
||||
|
||||
final Long transactionProcessingStrategyId = command.longValueOfParameterNamed("transactionProcessingStrategyId");
|
||||
final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(transactionProcessingStrategyId);
|
||||
|
||||
final String currencyCode = command.stringValueOfParameterNamed("currencyCode");
|
||||
final Set<Charge> charges = this.assembleSetOfCharges(command, currencyCode);
|
||||
final List<Charge> charges = this.assembleListOfProductCharges(command, currencyCode);
|
||||
|
||||
final LoanProduct loanproduct = LoanProduct.assembleFromJson(fund, loanTransactionProcessingStrategy, charges, command,
|
||||
this.aprCalculator);
|
||||
@@ -131,7 +130,6 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
||||
public CommandProcessingResult updateLoanProduct(final Long loanProductId, final JsonCommand command) {
|
||||
|
||||
try {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
|
||||
this.fromApiJsonDeserializer.validateForUpdate(command.json());
|
||||
@@ -141,8 +139,6 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
||||
|
||||
final Map<String, Object> changes = product.update(command, this.aprCalculator);
|
||||
|
||||
// associating fund with loan product at creation is optional for
|
||||
// now.
|
||||
if (changes.containsKey("fundId")) {
|
||||
final Long fundId = (Long) changes.get("fundId");
|
||||
final Fund fund = findFundByIdIfProvided(fundId);
|
||||
@@ -156,10 +152,13 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
||||
}
|
||||
|
||||
if (changes.containsKey("charges")) {
|
||||
final Set<Charge> charges = this.assembleSetOfCharges(command, product.getCurrency().getCode());
|
||||
product.update(charges);
|
||||
final List<Charge> productCharges = this.assembleListOfProductCharges(command, product.getCurrency().getCode());
|
||||
boolean updated = product.update(productCharges);
|
||||
if (!updated) {
|
||||
changes.remove("charges");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// accounting related changes
|
||||
boolean accountingTypeChanged = changes.containsKey("accountingRule");
|
||||
final Map<String, Object> accountingMappingChanges = accountMappingWritePlatformService.updateLoanProductToGLAccountMapping(
|
||||
@@ -183,29 +182,33 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
||||
|
||||
}
|
||||
|
||||
private Set<Charge> assembleSetOfCharges(final JsonCommand command, final String currencyCode) {
|
||||
private List<Charge> assembleListOfProductCharges(final JsonCommand command, final String currencyCode) {
|
||||
|
||||
final Set<Charge> charges = new HashSet<Charge>();
|
||||
final String[] chargesArray = command.arrayValueOfParameterNamed("charges");
|
||||
final List<Charge> charges = new ArrayList<Charge>();
|
||||
|
||||
String loanProductCurrencyCode = command.stringValueOfParameterNamed("currencyCode");
|
||||
if (loanProductCurrencyCode == null) {
|
||||
loanProductCurrencyCode = currencyCode;
|
||||
}
|
||||
|
||||
if (!ObjectUtils.isEmpty(chargesArray)) {
|
||||
for (final String chargeId : chargesArray) {
|
||||
if (command.parameterExists("charges")) {
|
||||
JsonArray chargesArray = command.arrayOfParameterNamed("charges");
|
||||
if (chargesArray != null) {
|
||||
for (int i = 0; i < chargesArray.size(); i++) {
|
||||
|
||||
final Long id = Long.valueOf(chargeId);
|
||||
final Charge charge = this.chargeRepository.findOne(id);
|
||||
if (charge == null || charge.isDeleted()) { throw new ChargeNotFoundException(id); }
|
||||
if (!charge.isActive()) { throw new ChargeIsNotActiveException(id, charge.getName()); }
|
||||
final JsonObject jsonObject = chargesArray.get(i).getAsJsonObject();
|
||||
if (jsonObject.has("id")) {
|
||||
final Long id = jsonObject.get("id").getAsLong();
|
||||
|
||||
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);
|
||||
final Charge charge = this.chargeRepository.findOneWithNotFoundDetection(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);
|
||||
}
|
||||
}
|
||||
charges.add(charge);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,6 +227,10 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
||||
final String name = command.stringValueOfParameterNamed("name");
|
||||
throw new PlatformDataIntegrityException("error.msg.product.loan.duplicate.name", "Loan product with name `" + name
|
||||
+ "` already exists", "name", name);
|
||||
} else if (realCause.getMessage().contains("Duplicate entry")) {
|
||||
Object[] args = null;
|
||||
throw new PlatformDataIntegrityException("error.msg.product.loan.duplicate.charge",
|
||||
"Loan product may only have one charge of each type.`", "charges", args);
|
||||
}
|
||||
|
||||
logAsErrorUnexpectedDataIntegrityException(dve);
|
||||
@@ -234,5 +241,4 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
||||
private void logAsErrorUnexpectedDataIntegrityException(final DataIntegrityViolationException dve) {
|
||||
logger.error(dve.getMessage(), dve);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user