feat(loan-products): add Loans A/C extension fields (collateral, eligibility, repayment, rate source, prepayment)
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, build-core) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, cucumber) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 7 of 10) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (progressive-loan, build-progressive-loan) (push) Canceled after 0s
Fineract Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (push) Canceled after 0s
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Canceled after 0s
Fineract Documentation build / build (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 10 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 2 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 3 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 4 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 5 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 6 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 8 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 9 of 10) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Canceled after 0s
Fineract Liquibase Only mode - PostgreSQL / test (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-1) (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with ActiveMQ (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with Kafka (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, build-core) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, cucumber) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 7 of 10) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (progressive-loan, build-progressive-loan) (push) Canceled after 0s
Fineract Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (push) Canceled after 0s
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Canceled after 0s
Fineract Documentation build / build (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 10 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 2 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 3 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 4 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 5 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 6 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 8 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 9 of 10) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Canceled after 0s
Fineract Liquibase Only mode - PostgreSQL / test (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-1) (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with ActiveMQ (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with Kafka (push) Canceled after 0s
Stores the Loans A/C (EMI) wizard's fields that have no home in Fineract's core loan-product schema on the same per-product satellite used for Advances: collateral/guarantor rules, borrower eligibility, disbursement, repayment mode, rate source / floating reset, and part-prepayment/foreclosure. Columns are loan_-prefixed so they never collide with the Advances columns on the shared table. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+169
@@ -295,6 +295,175 @@ public class LoanProductAdvanceExt {
|
|||||||
@Column(name = "cheque_block_lien_released")
|
@Column(name = "cheque_block_lien_released")
|
||||||
private Boolean chequeBlockLienReleased;
|
private Boolean chequeBlockLienReleased;
|
||||||
|
|
||||||
|
// ---- Loans A/C (EMI) wizard fields -------------------------------------
|
||||||
|
@Column(name = "loan_security_mandatory")
|
||||||
|
private String securityMandatory;
|
||||||
|
|
||||||
|
@Column(name = "loan_guarantors_required")
|
||||||
|
private Integer guarantorsRequired;
|
||||||
|
|
||||||
|
@Column(name = "loan_co_applicant")
|
||||||
|
private String coApplicant;
|
||||||
|
|
||||||
|
@Column(name = "loan_third_party_security")
|
||||||
|
private String thirdPartySecurity;
|
||||||
|
|
||||||
|
@Column(name = "loan_legal_opinion_required")
|
||||||
|
private Boolean legalOpinionRequired;
|
||||||
|
|
||||||
|
@Column(name = "loan_property_insurance_required")
|
||||||
|
private Boolean propertyInsuranceRequired;
|
||||||
|
|
||||||
|
@Column(name = "loan_register_charge")
|
||||||
|
private Boolean registerCharge;
|
||||||
|
|
||||||
|
@Column(name = "loan_release_security_on_closure")
|
||||||
|
private Boolean releaseSecurityOnClosure;
|
||||||
|
|
||||||
|
@Column(name = "loan_allow_multiple_securities")
|
||||||
|
private Boolean allowMultipleSecurities;
|
||||||
|
|
||||||
|
@Column(name = "loan_allow_third_party_deposit")
|
||||||
|
private Boolean allowThirdPartyDeposit;
|
||||||
|
|
||||||
|
@Column(name = "loan_min_age")
|
||||||
|
private Integer minAge;
|
||||||
|
|
||||||
|
@Column(name = "loan_max_age_at_maturity")
|
||||||
|
private Integer maxAgeAtMaturity;
|
||||||
|
|
||||||
|
@Column(name = "loan_min_cibil")
|
||||||
|
private Integer minCibil;
|
||||||
|
|
||||||
|
@Column(name = "loan_min_monthly_income")
|
||||||
|
private BigDecimal minMonthlyIncome;
|
||||||
|
|
||||||
|
@Column(name = "loan_max_foir")
|
||||||
|
private BigDecimal maxFoir;
|
||||||
|
|
||||||
|
@Column(name = "loan_max_loans_per_customer")
|
||||||
|
private Integer maxLoansPerCustomer;
|
||||||
|
|
||||||
|
@Column(name = "loan_disbursement_type")
|
||||||
|
private String disbursementType;
|
||||||
|
|
||||||
|
@Column(name = "loan_disbursement_mode")
|
||||||
|
private String disbursementMode;
|
||||||
|
|
||||||
|
@Column(name = "loan_undisbursed_interest")
|
||||||
|
private String undisbursedInterest;
|
||||||
|
|
||||||
|
@Column(name = "loan_pre_emi_interest")
|
||||||
|
private Boolean preEmiInterest;
|
||||||
|
|
||||||
|
@Column(name = "loan_emi_due_day")
|
||||||
|
private String emiDueDay;
|
||||||
|
|
||||||
|
@Column(name = "loan_holiday_rule")
|
||||||
|
private String holidayRule;
|
||||||
|
|
||||||
|
@Column(name = "loan_moratorium_months")
|
||||||
|
private Integer moratoriumMonths;
|
||||||
|
|
||||||
|
@Column(name = "loan_moratorium_interest")
|
||||||
|
private String moratoriumInterest;
|
||||||
|
|
||||||
|
@Column(name = "loan_variable_installments")
|
||||||
|
private Boolean variableInstallments;
|
||||||
|
|
||||||
|
@Column(name = "loan_repayment_mode")
|
||||||
|
private String repaymentMode;
|
||||||
|
|
||||||
|
@Column(name = "loan_linked_account_type")
|
||||||
|
private String linkedAccountType;
|
||||||
|
|
||||||
|
@Column(name = "loan_pdc_collection")
|
||||||
|
private String pdcCollection;
|
||||||
|
|
||||||
|
@Column(name = "loan_mandate_required")
|
||||||
|
private Boolean mandateRequired;
|
||||||
|
|
||||||
|
@Column(name = "loan_advance_emi")
|
||||||
|
private String advanceEmi;
|
||||||
|
|
||||||
|
@Column(name = "loan_rate_type")
|
||||||
|
private String rateType;
|
||||||
|
|
||||||
|
@Column(name = "loan_register_particular")
|
||||||
|
private String registerParticular;
|
||||||
|
|
||||||
|
@Column(name = "loan_apply_cibil_adjustment")
|
||||||
|
private Boolean applyCibilAdjustment;
|
||||||
|
|
||||||
|
@Column(name = "loan_rate_resolved_at")
|
||||||
|
private String rateResolvedAt;
|
||||||
|
|
||||||
|
@Column(name = "loan_calc_period")
|
||||||
|
private String calcPeriod;
|
||||||
|
|
||||||
|
@Column(name = "loan_interest_starts_from")
|
||||||
|
private String interestStartsFrom;
|
||||||
|
|
||||||
|
@Column(name = "loan_compounding")
|
||||||
|
private String compounding;
|
||||||
|
|
||||||
|
@Column(name = "loan_benchmark")
|
||||||
|
private String benchmark;
|
||||||
|
|
||||||
|
@Column(name = "loan_reset_frequency")
|
||||||
|
private String resetFrequency;
|
||||||
|
|
||||||
|
@Column(name = "loan_reset_change")
|
||||||
|
private String resetChange;
|
||||||
|
|
||||||
|
@Column(name = "loan_part_prepayment_allowed")
|
||||||
|
private Boolean partPrepaymentAllowed;
|
||||||
|
|
||||||
|
@Column(name = "loan_min_part_payment")
|
||||||
|
private BigDecimal minPartPayment;
|
||||||
|
|
||||||
|
@Column(name = "loan_allowed_on")
|
||||||
|
private String allowedOn;
|
||||||
|
|
||||||
|
@Column(name = "loan_part_payments_per_year")
|
||||||
|
private String partPaymentsPerYear;
|
||||||
|
|
||||||
|
@Column(name = "loan_part_prepayment_mode")
|
||||||
|
private String partPrepaymentMode;
|
||||||
|
|
||||||
|
@Column(name = "loan_foreclosure_floating_individual")
|
||||||
|
private BigDecimal foreclosureFloatingIndividual;
|
||||||
|
|
||||||
|
@Column(name = "loan_foreclosure_fixed_individual")
|
||||||
|
private BigDecimal foreclosureFixedIndividual;
|
||||||
|
|
||||||
|
@Column(name = "loan_foreclosure_non_individual")
|
||||||
|
private BigDecimal foreclosureNonIndividual;
|
||||||
|
|
||||||
|
@Column(name = "loan_foreclosure_takeover")
|
||||||
|
private BigDecimal foreclosureTakeover;
|
||||||
|
|
||||||
|
@Column(name = "loan_foreclosure_quote_valid_days")
|
||||||
|
private Integer foreclosureQuoteValidDays;
|
||||||
|
|
||||||
|
@Column(name = "loan_auto_close_on_zero_balance")
|
||||||
|
private Boolean autoCloseOnZeroBalance;
|
||||||
|
|
||||||
|
@Column(name = "loan_noc_letter")
|
||||||
|
private String nocLetter;
|
||||||
|
|
||||||
|
@Column(name = "loan_restructuring")
|
||||||
|
private String restructuring;
|
||||||
|
|
||||||
|
@Column(name = "loan_release_collateral_on_closure")
|
||||||
|
private Boolean releaseCollateralOnClosure;
|
||||||
|
|
||||||
|
@Column(name = "loan_top_up_allowed")
|
||||||
|
private Boolean topUpAllowed;
|
||||||
|
|
||||||
|
@Column(name = "loan_balance_transfer_out_allowed")
|
||||||
|
private Boolean balanceTransferOutAllowed;
|
||||||
|
|
||||||
public LoanProductAdvanceExt(final LoanProduct loanProduct) {
|
public LoanProductAdvanceExt(final LoanProduct loanProduct) {
|
||||||
this.loanProduct = loanProduct;
|
this.loanProduct = loanProduct;
|
||||||
this.loanProductId = loanProduct.getId();
|
this.loanProductId = loanProduct.getId();
|
||||||
|
|||||||
+50
-1
@@ -37,10 +37,15 @@ import jakarta.ws.rs.Produces;
|
|||||||
import jakarta.ws.rs.QueryParam;
|
import jakarta.ws.rs.QueryParam;
|
||||||
import jakarta.ws.rs.core.Context;
|
import jakarta.ws.rs.core.Context;
|
||||||
import jakarta.ws.rs.core.MediaType;
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
import jakarta.ws.rs.core.MultivaluedMap;
|
||||||
import jakarta.ws.rs.core.UriInfo;
|
import jakarta.ws.rs.core.UriInfo;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -58,6 +63,7 @@ import org.apache.fineract.commands.domain.CommandWrapper;
|
|||||||
import org.apache.fineract.commands.service.CommandWrapperBuilder;
|
import org.apache.fineract.commands.service.CommandWrapperBuilder;
|
||||||
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
|
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||||
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
|
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
|
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
|
||||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||||
import org.apache.fineract.infrastructure.core.api.ApiFacingEnum;
|
import org.apache.fineract.infrastructure.core.api.ApiFacingEnum;
|
||||||
@@ -222,11 +228,54 @@ public class LoanProductsApiResource {
|
|||||||
return this.productMixDataApiJsonSerializer.serialize(settings, productMixes, PRODUCT_MIX_DATA_PARAMETERS);
|
return this.productMixDataApiJsonSerializer.serialize(settings, productMixes, PRODUCT_MIX_DATA_PARAMETERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Collection<LoanProductData> products = this.loanProductReadPlatformService.retrieveAllLoanProducts();
|
final Collection<LoanProductData> products = enrichAndFilterProducts(
|
||||||
|
this.loanProductReadPlatformService.retrieveAllLoanProducts(), uriInfo);
|
||||||
|
|
||||||
return this.toApiJsonSerializer.serialize(settings, products, LOAN_PRODUCT_DATA_PARAMETERS);
|
return this.toApiJsonSerializer.serialize(settings, products, LOAN_PRODUCT_DATA_PARAMETERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds each product's category and type ("Advances A/C" or "Loans A/C" and its sub type) to the list, and applies
|
||||||
|
* the optional filters {@code activeOnly}, {@code productTypeGroup} and {@code productTypeSubGroup}. With none of
|
||||||
|
* them given the list holds the same products as before, each now carrying its classification.
|
||||||
|
*/
|
||||||
|
private Collection<LoanProductData> enrichAndFilterProducts(final Collection<LoanProductData> products, final UriInfo uriInfo) {
|
||||||
|
final MultivaluedMap<String, String> query = uriInfo.getQueryParameters();
|
||||||
|
final boolean activeOnly = Boolean.parseBoolean(query.getFirst("activeOnly"));
|
||||||
|
final String group = trimToNull(query.getFirst("productTypeGroup"));
|
||||||
|
final String subGroup = trimToNull(query.getFirst("productTypeSubGroup"));
|
||||||
|
final Map<Long, Map<String, Object>> extensions = this.loanProductAdvanceExtService.retrieveAllAsMap();
|
||||||
|
final LocalDate today = DateUtils.getBusinessLocalDate();
|
||||||
|
|
||||||
|
final List<LoanProductData> result = new ArrayList<>();
|
||||||
|
for (final LoanProductData product : products) {
|
||||||
|
final Map<String, Object> ext = extensions.getOrDefault(product.getId(), Collections.emptyMap());
|
||||||
|
if (activeOnly && !isActiveOn(product, today)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (group != null && !group.equalsIgnoreCase(String.valueOf(ext.get("productTypeGroup")))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (subGroup != null && !subGroup.equalsIgnoreCase(String.valueOf(ext.get("productTypeSubGroup")))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
product.setAdvanceExtensions(new LinkedHashMap<>(ext));
|
||||||
|
result.add(product);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A product is active from its start date until its close date; either end may be open. */
|
||||||
|
private static boolean isActiveOn(final LoanProductData product, final LocalDate date) {
|
||||||
|
final LocalDate start = product.getStartDate();
|
||||||
|
final LocalDate close = product.getCloseDate();
|
||||||
|
return (start == null || !start.isAfter(date)) && (close == null || !close.isBefore(date));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String trimToNull(final String value) {
|
||||||
|
return value == null || value.isBlank() ? null : value.trim();
|
||||||
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("template")
|
@Path("template")
|
||||||
@Consumes({ MediaType.APPLICATION_JSON })
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
|||||||
+142
-1
@@ -61,7 +61,22 @@ public class LoanProductAdvanceExtService {
|
|||||||
"chequeBookSizes", "chequeMaxBooksOutstanding", "chequeReissueWhenLeaves", "chequeFirstBookFree",
|
"chequeBookSizes", "chequeMaxBooksOutstanding", "chequeReissueWhenLeaves", "chequeFirstBookFree",
|
||||||
"chequeFreeBooksPerYear", "chequeNamePrinted", "chequePrintDescription", "chequeStopPaymentAllowed",
|
"chequeFreeBooksPerYear", "chequeNamePrinted", "chequePrintDescription", "chequeStopPaymentAllowed",
|
||||||
"chequeMaintainStockRegister", "chequeAllowWithdrawalSlip", "chequeBlockNpa", "chequeBlockLimitExpired",
|
"chequeMaintainStockRegister", "chequeAllowWithdrawalSlip", "chequeBlockNpa", "chequeBlockLimitExpired",
|
||||||
"chequeBlockOverDp", "chequeBlockFrozen", "chequeBlockLienReleased" };
|
"chequeBlockOverDp", "chequeBlockFrozen", "chequeBlockLienReleased",
|
||||||
|
// Loans A/C (EMI) wizard fields
|
||||||
|
"securityMandatory", "guarantorsRequired", "coApplicant", "thirdPartySecurity",
|
||||||
|
"legalOpinionRequired", "propertyInsuranceRequired", "registerCharge", "releaseSecurityOnClosure",
|
||||||
|
"allowMultipleSecurities", "allowThirdPartyDeposit", "minAge", "maxAgeAtMaturity",
|
||||||
|
"minCibil", "minMonthlyIncome", "maxFoir", "maxLoansPerCustomer",
|
||||||
|
"disbursementType", "disbursementMode", "undisbursedInterest", "preEmiInterest",
|
||||||
|
"emiDueDay", "holidayRule", "moratoriumMonths", "moratoriumInterest",
|
||||||
|
"variableInstallments", "repaymentMode", "linkedAccountType", "pdcCollection",
|
||||||
|
"mandateRequired", "advanceEmi", "rateType", "registerParticular",
|
||||||
|
"applyCibilAdjustment", "rateResolvedAt", "calcPeriod", "interestStartsFrom",
|
||||||
|
"compounding", "benchmark", "resetFrequency", "resetChange",
|
||||||
|
"partPrepaymentAllowed", "minPartPayment", "allowedOn", "partPaymentsPerYear",
|
||||||
|
"partPrepaymentMode", "foreclosureFloatingIndividual", "foreclosureFixedIndividual", "foreclosureNonIndividual",
|
||||||
|
"foreclosureTakeover", "foreclosureQuoteValidDays", "autoCloseOnZeroBalance", "nocLetter",
|
||||||
|
"restructuring", "releaseCollateralOnClosure", "topUpAllowed", "balanceTransferOutAllowed" };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert or partial-update the satellite for this product. Returns the fields that actually changed so the
|
* Insert or partial-update the satellite for this product. Returns the fields that actually changed so the
|
||||||
@@ -84,6 +99,18 @@ public class LoanProductAdvanceExtService {
|
|||||||
.orElseGet(LinkedHashMap::new);
|
.orElseGet(LinkedHashMap::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every product's satellite in one query, keyed by loan product id. Used by the product list so a screen can
|
||||||
|
* show and filter products by category and type without one extra call per product.
|
||||||
|
*/
|
||||||
|
public Map<Long, Map<String, Object>> retrieveAllAsMap() {
|
||||||
|
final Map<Long, Map<String, Object>> byProduct = new LinkedHashMap<>();
|
||||||
|
for (final LoanProductAdvanceExt ext : this.repository.findAll()) {
|
||||||
|
byProduct.put(ext.getLoanProductId(), toMap(ext));
|
||||||
|
}
|
||||||
|
return byProduct;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean hasAnyAdvanceParameter(final JsonCommand command) {
|
private boolean hasAnyAdvanceParameter(final JsonCommand command) {
|
||||||
for (final String param : ADVANCE_PARAMETERS) {
|
for (final String param : ADVANCE_PARAMETERS) {
|
||||||
if (command.parameterExists(param)) {
|
if (command.parameterExists(param)) {
|
||||||
@@ -205,6 +232,63 @@ public class LoanProductAdvanceExtService {
|
|||||||
setBoolean(command, "chequeBlockFrozen", ext::getChequeBlockFrozen, ext::setChequeBlockFrozen, changes);
|
setBoolean(command, "chequeBlockFrozen", ext::getChequeBlockFrozen, ext::setChequeBlockFrozen, changes);
|
||||||
setBoolean(command, "chequeBlockLienReleased", ext::getChequeBlockLienReleased, ext::setChequeBlockLienReleased,
|
setBoolean(command, "chequeBlockLienReleased", ext::getChequeBlockLienReleased, ext::setChequeBlockLienReleased,
|
||||||
changes);
|
changes);
|
||||||
|
// Loans A/C (EMI) wizard fields
|
||||||
|
setString(command, "securityMandatory", ext::getSecurityMandatory, ext::setSecurityMandatory, changes);
|
||||||
|
setInteger(command, "guarantorsRequired", ext::getGuarantorsRequired, ext::setGuarantorsRequired, changes);
|
||||||
|
setString(command, "coApplicant", ext::getCoApplicant, ext::setCoApplicant, changes);
|
||||||
|
setString(command, "thirdPartySecurity", ext::getThirdPartySecurity, ext::setThirdPartySecurity, changes);
|
||||||
|
setBoolean(command, "legalOpinionRequired", ext::getLegalOpinionRequired, ext::setLegalOpinionRequired, changes);
|
||||||
|
setBoolean(command, "propertyInsuranceRequired", ext::getPropertyInsuranceRequired, ext::setPropertyInsuranceRequired, changes);
|
||||||
|
setBoolean(command, "registerCharge", ext::getRegisterCharge, ext::setRegisterCharge, changes);
|
||||||
|
setBoolean(command, "releaseSecurityOnClosure", ext::getReleaseSecurityOnClosure, ext::setReleaseSecurityOnClosure, changes);
|
||||||
|
setBoolean(command, "allowMultipleSecurities", ext::getAllowMultipleSecurities, ext::setAllowMultipleSecurities, changes);
|
||||||
|
setBoolean(command, "allowThirdPartyDeposit", ext::getAllowThirdPartyDeposit, ext::setAllowThirdPartyDeposit, changes);
|
||||||
|
setInteger(command, "minAge", ext::getMinAge, ext::setMinAge, changes);
|
||||||
|
setInteger(command, "maxAgeAtMaturity", ext::getMaxAgeAtMaturity, ext::setMaxAgeAtMaturity, changes);
|
||||||
|
setInteger(command, "minCibil", ext::getMinCibil, ext::setMinCibil, changes);
|
||||||
|
setDecimal(command, "minMonthlyIncome", ext::getMinMonthlyIncome, ext::setMinMonthlyIncome, changes);
|
||||||
|
setDecimal(command, "maxFoir", ext::getMaxFoir, ext::setMaxFoir, changes);
|
||||||
|
setInteger(command, "maxLoansPerCustomer", ext::getMaxLoansPerCustomer, ext::setMaxLoansPerCustomer, changes);
|
||||||
|
setString(command, "disbursementType", ext::getDisbursementType, ext::setDisbursementType, changes);
|
||||||
|
setString(command, "disbursementMode", ext::getDisbursementMode, ext::setDisbursementMode, changes);
|
||||||
|
setString(command, "undisbursedInterest", ext::getUndisbursedInterest, ext::setUndisbursedInterest, changes);
|
||||||
|
setBoolean(command, "preEmiInterest", ext::getPreEmiInterest, ext::setPreEmiInterest, changes);
|
||||||
|
setString(command, "emiDueDay", ext::getEmiDueDay, ext::setEmiDueDay, changes);
|
||||||
|
setString(command, "holidayRule", ext::getHolidayRule, ext::setHolidayRule, changes);
|
||||||
|
setInteger(command, "moratoriumMonths", ext::getMoratoriumMonths, ext::setMoratoriumMonths, changes);
|
||||||
|
setString(command, "moratoriumInterest", ext::getMoratoriumInterest, ext::setMoratoriumInterest, changes);
|
||||||
|
setBoolean(command, "variableInstallments", ext::getVariableInstallments, ext::setVariableInstallments, changes);
|
||||||
|
setString(command, "repaymentMode", ext::getRepaymentMode, ext::setRepaymentMode, changes);
|
||||||
|
setString(command, "linkedAccountType", ext::getLinkedAccountType, ext::setLinkedAccountType, changes);
|
||||||
|
setString(command, "pdcCollection", ext::getPdcCollection, ext::setPdcCollection, changes);
|
||||||
|
setBoolean(command, "mandateRequired", ext::getMandateRequired, ext::setMandateRequired, changes);
|
||||||
|
setString(command, "advanceEmi", ext::getAdvanceEmi, ext::setAdvanceEmi, changes);
|
||||||
|
setString(command, "rateType", ext::getRateType, ext::setRateType, changes);
|
||||||
|
setString(command, "registerParticular", ext::getRegisterParticular, ext::setRegisterParticular, changes);
|
||||||
|
setBoolean(command, "applyCibilAdjustment", ext::getApplyCibilAdjustment, ext::setApplyCibilAdjustment, changes);
|
||||||
|
setString(command, "rateResolvedAt", ext::getRateResolvedAt, ext::setRateResolvedAt, changes);
|
||||||
|
setString(command, "calcPeriod", ext::getCalcPeriod, ext::setCalcPeriod, changes);
|
||||||
|
setString(command, "interestStartsFrom", ext::getInterestStartsFrom, ext::setInterestStartsFrom, changes);
|
||||||
|
setString(command, "compounding", ext::getCompounding, ext::setCompounding, changes);
|
||||||
|
setString(command, "benchmark", ext::getBenchmark, ext::setBenchmark, changes);
|
||||||
|
setString(command, "resetFrequency", ext::getResetFrequency, ext::setResetFrequency, changes);
|
||||||
|
setString(command, "resetChange", ext::getResetChange, ext::setResetChange, changes);
|
||||||
|
setBoolean(command, "partPrepaymentAllowed", ext::getPartPrepaymentAllowed, ext::setPartPrepaymentAllowed, changes);
|
||||||
|
setDecimal(command, "minPartPayment", ext::getMinPartPayment, ext::setMinPartPayment, changes);
|
||||||
|
setString(command, "allowedOn", ext::getAllowedOn, ext::setAllowedOn, changes);
|
||||||
|
setString(command, "partPaymentsPerYear", ext::getPartPaymentsPerYear, ext::setPartPaymentsPerYear, changes);
|
||||||
|
setString(command, "partPrepaymentMode", ext::getPartPrepaymentMode, ext::setPartPrepaymentMode, changes);
|
||||||
|
setDecimal(command, "foreclosureFloatingIndividual", ext::getForeclosureFloatingIndividual, ext::setForeclosureFloatingIndividual, changes);
|
||||||
|
setDecimal(command, "foreclosureFixedIndividual", ext::getForeclosureFixedIndividual, ext::setForeclosureFixedIndividual, changes);
|
||||||
|
setDecimal(command, "foreclosureNonIndividual", ext::getForeclosureNonIndividual, ext::setForeclosureNonIndividual, changes);
|
||||||
|
setDecimal(command, "foreclosureTakeover", ext::getForeclosureTakeover, ext::setForeclosureTakeover, changes);
|
||||||
|
setInteger(command, "foreclosureQuoteValidDays", ext::getForeclosureQuoteValidDays, ext::setForeclosureQuoteValidDays, changes);
|
||||||
|
setBoolean(command, "autoCloseOnZeroBalance", ext::getAutoCloseOnZeroBalance, ext::setAutoCloseOnZeroBalance, changes);
|
||||||
|
setString(command, "nocLetter", ext::getNocLetter, ext::setNocLetter, changes);
|
||||||
|
setString(command, "restructuring", ext::getRestructuring, ext::setRestructuring, changes);
|
||||||
|
setBoolean(command, "releaseCollateralOnClosure", ext::getReleaseCollateralOnClosure, ext::setReleaseCollateralOnClosure, changes);
|
||||||
|
setBoolean(command, "topUpAllowed", ext::getTopUpAllowed, ext::setTopUpAllowed, changes);
|
||||||
|
setBoolean(command, "balanceTransferOutAllowed", ext::getBalanceTransferOutAllowed, ext::setBalanceTransferOutAllowed, changes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- typed setters: only write params that are present, and only report real changes ----------
|
// ---- typed setters: only write params that are present, and only report real changes ----------
|
||||||
@@ -368,6 +452,63 @@ public class LoanProductAdvanceExtService {
|
|||||||
map.put("chequeBlockOverDp", ext.getChequeBlockOverDp());
|
map.put("chequeBlockOverDp", ext.getChequeBlockOverDp());
|
||||||
map.put("chequeBlockFrozen", ext.getChequeBlockFrozen());
|
map.put("chequeBlockFrozen", ext.getChequeBlockFrozen());
|
||||||
map.put("chequeBlockLienReleased", ext.getChequeBlockLienReleased());
|
map.put("chequeBlockLienReleased", ext.getChequeBlockLienReleased());
|
||||||
|
// Loans A/C (EMI) wizard fields
|
||||||
|
map.put("securityMandatory", ext.getSecurityMandatory());
|
||||||
|
map.put("guarantorsRequired", ext.getGuarantorsRequired());
|
||||||
|
map.put("coApplicant", ext.getCoApplicant());
|
||||||
|
map.put("thirdPartySecurity", ext.getThirdPartySecurity());
|
||||||
|
map.put("legalOpinionRequired", ext.getLegalOpinionRequired());
|
||||||
|
map.put("propertyInsuranceRequired", ext.getPropertyInsuranceRequired());
|
||||||
|
map.put("registerCharge", ext.getRegisterCharge());
|
||||||
|
map.put("releaseSecurityOnClosure", ext.getReleaseSecurityOnClosure());
|
||||||
|
map.put("allowMultipleSecurities", ext.getAllowMultipleSecurities());
|
||||||
|
map.put("allowThirdPartyDeposit", ext.getAllowThirdPartyDeposit());
|
||||||
|
map.put("minAge", ext.getMinAge());
|
||||||
|
map.put("maxAgeAtMaturity", ext.getMaxAgeAtMaturity());
|
||||||
|
map.put("minCibil", ext.getMinCibil());
|
||||||
|
map.put("minMonthlyIncome", ext.getMinMonthlyIncome());
|
||||||
|
map.put("maxFoir", ext.getMaxFoir());
|
||||||
|
map.put("maxLoansPerCustomer", ext.getMaxLoansPerCustomer());
|
||||||
|
map.put("disbursementType", ext.getDisbursementType());
|
||||||
|
map.put("disbursementMode", ext.getDisbursementMode());
|
||||||
|
map.put("undisbursedInterest", ext.getUndisbursedInterest());
|
||||||
|
map.put("preEmiInterest", ext.getPreEmiInterest());
|
||||||
|
map.put("emiDueDay", ext.getEmiDueDay());
|
||||||
|
map.put("holidayRule", ext.getHolidayRule());
|
||||||
|
map.put("moratoriumMonths", ext.getMoratoriumMonths());
|
||||||
|
map.put("moratoriumInterest", ext.getMoratoriumInterest());
|
||||||
|
map.put("variableInstallments", ext.getVariableInstallments());
|
||||||
|
map.put("repaymentMode", ext.getRepaymentMode());
|
||||||
|
map.put("linkedAccountType", ext.getLinkedAccountType());
|
||||||
|
map.put("pdcCollection", ext.getPdcCollection());
|
||||||
|
map.put("mandateRequired", ext.getMandateRequired());
|
||||||
|
map.put("advanceEmi", ext.getAdvanceEmi());
|
||||||
|
map.put("rateType", ext.getRateType());
|
||||||
|
map.put("registerParticular", ext.getRegisterParticular());
|
||||||
|
map.put("applyCibilAdjustment", ext.getApplyCibilAdjustment());
|
||||||
|
map.put("rateResolvedAt", ext.getRateResolvedAt());
|
||||||
|
map.put("calcPeriod", ext.getCalcPeriod());
|
||||||
|
map.put("interestStartsFrom", ext.getInterestStartsFrom());
|
||||||
|
map.put("compounding", ext.getCompounding());
|
||||||
|
map.put("benchmark", ext.getBenchmark());
|
||||||
|
map.put("resetFrequency", ext.getResetFrequency());
|
||||||
|
map.put("resetChange", ext.getResetChange());
|
||||||
|
map.put("partPrepaymentAllowed", ext.getPartPrepaymentAllowed());
|
||||||
|
map.put("minPartPayment", ext.getMinPartPayment());
|
||||||
|
map.put("allowedOn", ext.getAllowedOn());
|
||||||
|
map.put("partPaymentsPerYear", ext.getPartPaymentsPerYear());
|
||||||
|
map.put("partPrepaymentMode", ext.getPartPrepaymentMode());
|
||||||
|
map.put("foreclosureFloatingIndividual", ext.getForeclosureFloatingIndividual());
|
||||||
|
map.put("foreclosureFixedIndividual", ext.getForeclosureFixedIndividual());
|
||||||
|
map.put("foreclosureNonIndividual", ext.getForeclosureNonIndividual());
|
||||||
|
map.put("foreclosureTakeover", ext.getForeclosureTakeover());
|
||||||
|
map.put("foreclosureQuoteValidDays", ext.getForeclosureQuoteValidDays());
|
||||||
|
map.put("autoCloseOnZeroBalance", ext.getAutoCloseOnZeroBalance());
|
||||||
|
map.put("nocLetter", ext.getNocLetter());
|
||||||
|
map.put("restructuring", ext.getRestructuring());
|
||||||
|
map.put("releaseCollateralOnClosure", ext.getReleaseCollateralOnClosure());
|
||||||
|
map.put("topUpAllowed", ext.getTopUpAllowed());
|
||||||
|
map.put("balanceTransferOutAllowed", ext.getBalanceTransferOutAllowed());
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -622,4 +622,5 @@
|
|||||||
<include file="parts/0594_loan_rate_register_product_master.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0594_loan_rate_register_product_master.xml" relativeToChangelogFile="true"/>
|
||||||
<include file="parts/0595_seed_loan_rate_register_gl_accounts.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0595_seed_loan_rate_register_gl_accounts.xml" relativeToChangelogFile="true"/>
|
||||||
<include file="parts/0596_enable_delinquency_maker_checker.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0596_enable_delinquency_maker_checker.xml" relativeToChangelogFile="true"/>
|
||||||
|
<include file="parts/0597_add_loan_product_loans_ext_fields.xml" relativeToChangelogFile="true"/>
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
|
|||||||
+90
@@ -0,0 +1,90 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
or more contributor license agreements. See the NOTICE file
|
||||||
|
distributed with this work for additional information
|
||||||
|
regarding copyright ownership. The ASF licenses this file
|
||||||
|
to you under the Apache License, Version 2.0 (the
|
||||||
|
"License"); you may not use this file except in compliance
|
||||||
|
with the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing,
|
||||||
|
software distributed under the License is distributed on an
|
||||||
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, either express or implied. See the License for the
|
||||||
|
specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||||
|
|
||||||
|
<!-- Loans A/C (EMI) wizard fields that Fineract's loan-product schema has no home for: collateral and
|
||||||
|
guarantor rules, borrower eligibility, disbursement, repayment mode, rate source / floating reset,
|
||||||
|
part-prepayment and foreclosure. Stored on the same per-product satellite as the Advances fields.
|
||||||
|
The columns are prefixed loan_ so they never clash with an Advances column. -->
|
||||||
|
<changeSet author="cbsnexora" id="0597_add_loan_product_loans_ext_fields">
|
||||||
|
<addColumn tableName="m_product_loan_advance_ext">
|
||||||
|
<column name="loan_security_mandatory" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_guarantors_required" type="INT"/>
|
||||||
|
<column name="loan_co_applicant" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_third_party_security" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_legal_opinion_required" type="BOOLEAN"/>
|
||||||
|
<column name="loan_property_insurance_required" type="BOOLEAN"/>
|
||||||
|
<column name="loan_register_charge" type="BOOLEAN"/>
|
||||||
|
<column name="loan_release_security_on_closure" type="BOOLEAN"/>
|
||||||
|
<column name="loan_allow_multiple_securities" type="BOOLEAN"/>
|
||||||
|
<column name="loan_allow_third_party_deposit" type="BOOLEAN"/>
|
||||||
|
<column name="loan_min_age" type="INT"/>
|
||||||
|
<column name="loan_max_age_at_maturity" type="INT"/>
|
||||||
|
<column name="loan_min_cibil" type="INT"/>
|
||||||
|
<column name="loan_min_monthly_income" type="DECIMAL(19,6)"/>
|
||||||
|
<column name="loan_max_foir" type="DECIMAL(19,6)"/>
|
||||||
|
<column name="loan_max_loans_per_customer" type="INT"/>
|
||||||
|
<column name="loan_disbursement_type" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_disbursement_mode" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_undisbursed_interest" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_pre_emi_interest" type="BOOLEAN"/>
|
||||||
|
<column name="loan_emi_due_day" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_holiday_rule" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_moratorium_months" type="INT"/>
|
||||||
|
<column name="loan_moratorium_interest" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_variable_installments" type="BOOLEAN"/>
|
||||||
|
<column name="loan_repayment_mode" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_linked_account_type" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_pdc_collection" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_mandate_required" type="BOOLEAN"/>
|
||||||
|
<column name="loan_advance_emi" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_rate_type" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_register_particular" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_apply_cibil_adjustment" type="BOOLEAN"/>
|
||||||
|
<column name="loan_rate_resolved_at" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_calc_period" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_interest_starts_from" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_compounding" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_benchmark" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_reset_frequency" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_reset_change" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_part_prepayment_allowed" type="BOOLEAN"/>
|
||||||
|
<column name="loan_min_part_payment" type="DECIMAL(19,6)"/>
|
||||||
|
<column name="loan_allowed_on" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_part_payments_per_year" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_part_prepayment_mode" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_foreclosure_floating_individual" type="DECIMAL(19,6)"/>
|
||||||
|
<column name="loan_foreclosure_fixed_individual" type="DECIMAL(19,6)"/>
|
||||||
|
<column name="loan_foreclosure_non_individual" type="DECIMAL(19,6)"/>
|
||||||
|
<column name="loan_foreclosure_takeover" type="DECIMAL(19,6)"/>
|
||||||
|
<column name="loan_foreclosure_quote_valid_days" type="INT"/>
|
||||||
|
<column name="loan_auto_close_on_zero_balance" type="BOOLEAN"/>
|
||||||
|
<column name="loan_noc_letter" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_restructuring" type="VARCHAR(100)"/>
|
||||||
|
<column name="loan_release_collateral_on_closure" type="BOOLEAN"/>
|
||||||
|
<column name="loan_top_up_allowed" type="BOOLEAN"/>
|
||||||
|
<column name="loan_balance_transfer_out_allowed" type="BOOLEAN"/>
|
||||||
|
</addColumn>
|
||||||
|
</changeSet>
|
||||||
|
</databaseChangeLog>
|
||||||
Reference in New Issue
Block a user