Merge pull request #859 from pramodn02/MIFOSX-1081
MIFOSX-1081 - Added Non Performing assets to Loan
This commit is contained in:
@@ -5800,6 +5800,7 @@ GET https://DomainName/api/v1/loans/{loanId}
|
||||
"canDisburse":false,
|
||||
"emiAmountVariations": [],
|
||||
"inArrears": true,
|
||||
"isNPA":false,
|
||||
"overdueCharges": [
|
||||
{
|
||||
"id": 20,
|
||||
@@ -6087,7 +6088,8 @@ GET https://DomainName/mifosng-provider/api/v1/loans
|
||||
]
|
||||
},
|
||||
"feeChargesAtDisbursementCharged": 0,
|
||||
"inArrears":false
|
||||
"inArrears":false,
|
||||
"isNPA":false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -9656,7 +9658,8 @@ GET https://DomainName/api/v1/loanproducts/{productId}
|
||||
"glCode": "11"
|
||||
}
|
||||
},
|
||||
"multiDisburseLoan":true,"maxTrancheCount":3,"outstandingLoanBalance":36000.000000
|
||||
"multiDisburseLoan":true,"maxTrancheCount":3,"outstandingLoanBalance":36000.000000,
|
||||
"overdueDaysForNPA":2
|
||||
]
|
||||
}
|
||||
</code>
|
||||
@@ -9698,7 +9701,7 @@ GET https://DomainName/api/v1/loanproducts/{productId}
|
||||
numberOfRepaymentVariationsForBorrowerCycle,
|
||||
interestRateVariationsForBorrowerCycle,
|
||||
multiDisburseLoan,maxTrancheCount,
|
||||
outstandingLoanBalance
|
||||
outstandingLoanBalance,overdueDaysForNPA
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -9769,6 +9772,7 @@ Request Body:
|
||||
"feeToIncomeAccountMappings":[],
|
||||
"penaltyToIncomeAccountMappings":[],
|
||||
"charges":[],
|
||||
"overdueDaysForNPA":2,
|
||||
"dateFormat":"dd MMMM yyyy",
|
||||
"locale":"en",
|
||||
"fundSourceAccountId":1,
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
ALTER TABLE `m_product_loan`
|
||||
ADD COLUMN `overdue_days_for_npa` SMALLINT(5) NULL DEFAULT NULL AFTER `grace_on_arrears_ageing`;
|
||||
|
||||
ALTER TABLE `m_loan`
|
||||
ADD COLUMN `is_npa` TINYINT(1) NOT NULL DEFAULT '0' AFTER `grace_on_arrears_ageing`;
|
||||
|
||||
INSERT INTO `job` (`name`, `display_name`, `cron_expression`, `create_time`) VALUES ('Update Non Performing Assets', 'Update Non Performing Assets', '0 0 0 1/1 * ? *', now());
|
||||
+2
-1
@@ -13,7 +13,8 @@ public enum JobName {
|
||||
PAY_DUE_SAVINGS_CHARGES("Pay Due Savings Charges"), //
|
||||
APPLY_CHARGE_TO_OVERDUE_LOAN_INSTALLMENT("Apply penalty to overdue loans"),
|
||||
EXECUTE_STANDING_INSTRUCTIONS("Execute Standing Instruction"),
|
||||
ADD_ACCRUAL_ENTRIES("Add Accrual Transactions");
|
||||
ADD_ACCRUAL_ENTRIES("Add Accrual Transactions"),
|
||||
UPDATE_NPA("Update Non Performing Assets");
|
||||
|
||||
private final String name;
|
||||
|
||||
|
||||
+25
-13
@@ -158,6 +158,8 @@ public class LoanAccountData {
|
||||
|
||||
private final Boolean inArrears;
|
||||
|
||||
private final Boolean isNPA;
|
||||
|
||||
private final Collection<ChargeData> overdueCharges;
|
||||
|
||||
/**
|
||||
@@ -244,6 +246,7 @@ public class LoanAccountData {
|
||||
final Map<Long, LoanBorrowerCycleData> memberVariations = null;
|
||||
final LoanProductData product = null;
|
||||
final Boolean inArrears = null;
|
||||
final Boolean isNPA = null;
|
||||
final Collection<ChargeData> overdueCharges = null;
|
||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
||||
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
||||
@@ -258,7 +261,7 @@ public class LoanAccountData {
|
||||
chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
||||
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount,
|
||||
disbursementData, multiDisburseLoan, fixedEmiAmount, maxOutstandingLoanBalance, emiAmountVariations, memberVariations,
|
||||
product, inArrears, graceOnArrearsAgeing, overdueCharges);
|
||||
product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -345,6 +348,7 @@ public class LoanAccountData {
|
||||
final Map<Long, LoanBorrowerCycleData> memberVariations = null;
|
||||
final LoanProductData product = null;
|
||||
final Boolean inArrears = null;
|
||||
final Boolean isNPA = null;
|
||||
final Collection<ChargeData> overdueCharges = null;
|
||||
|
||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
||||
@@ -359,7 +363,8 @@ public class LoanAccountData {
|
||||
interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions,
|
||||
loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter,
|
||||
notes, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, fixedEmiAmount,
|
||||
maxOutstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges);
|
||||
maxOutstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges,
|
||||
isNPA);
|
||||
}
|
||||
|
||||
public static LoanAccountData populateClientDefaults(final LoanAccountData acc, final LoanAccountData clientAcc) {
|
||||
@@ -380,7 +385,8 @@ public class LoanAccountData {
|
||||
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
|
||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
||||
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges);
|
||||
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
||||
acc.isNPA);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -468,6 +474,7 @@ public class LoanAccountData {
|
||||
final Map<Long, LoanBorrowerCycleData> memberVariations = null;
|
||||
final LoanProductData product = null;
|
||||
final Boolean inArrears = null;
|
||||
final Boolean isNPA = null;
|
||||
final Collection<ChargeData> overdueCharges = null;
|
||||
|
||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
||||
@@ -482,7 +489,7 @@ public class LoanAccountData {
|
||||
interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions,
|
||||
loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter,
|
||||
notes, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, fixedEmiAmount, maxOutstandingBalance,
|
||||
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges);
|
||||
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA);
|
||||
}
|
||||
|
||||
public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) {
|
||||
@@ -502,7 +509,8 @@ public class LoanAccountData {
|
||||
acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
|
||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
||||
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges);
|
||||
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
||||
acc.isNPA);
|
||||
}
|
||||
|
||||
public static LoanAccountData loanProductWithTemplateDefaults(final LoanProductData product,
|
||||
@@ -609,6 +617,7 @@ public class LoanAccountData {
|
||||
final BigDecimal fixedEmi = null;
|
||||
Map<Long, LoanBorrowerCycleData> memberVariations = null;
|
||||
final Boolean inArrears = null;
|
||||
final Boolean isNPA = null;
|
||||
|
||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType,
|
||||
product.getId(), product.getName(), product.getDescription(), product.getFundId(), product.getFundName(), loanPurposeId,
|
||||
@@ -625,7 +634,7 @@ public class LoanAccountData {
|
||||
loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter,
|
||||
notes, accountLinkingOptions, linkedAccount, disbursementData, product.getMultiDisburseLoan(), fixedEmi,
|
||||
product.getOutstandingLoanBalance(), emiAmountVariations, memberVariations, product, inArrears,
|
||||
product.getGraceOnArrearsAgeing(), product.overdueFeeCharges());
|
||||
product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), isNPA);
|
||||
}
|
||||
|
||||
public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) {
|
||||
@@ -677,7 +686,7 @@ public class LoanAccountData {
|
||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, notes, acc.accountLinkingOptions,
|
||||
acc.linkedAccount, acc.disbursementDetails, product.getMultiDisburseLoan(), acc.fixedEmiAmount,
|
||||
product.getOutstandingLoanBalance(), acc.emiAmountVariations, acc.memberVariations, product, acc.inArrears,
|
||||
product.getGraceOnArrearsAgeing(), product.overdueFeeCharges());
|
||||
product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), acc.isNPA);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -699,7 +708,7 @@ public class LoanAccountData {
|
||||
final LoanSummaryData loanSummary, final BigDecimal feeChargesDueAtDisbursementCharged,
|
||||
final Boolean syncDisbursementWithMeeting, final Integer loancounter, final Integer loanProductCounter,
|
||||
final Boolean multiDisburseLoan, final BigDecimal fixedEmiAmont, final BigDecimal outstandingLoanBalance,
|
||||
final Boolean inArrears, final Integer graceOnArrearsAgeing) {
|
||||
final Boolean inArrears, final Integer graceOnArrearsAgeing, final Boolean isNPA) {
|
||||
|
||||
final LoanScheduleData repaymentSchedule = null;
|
||||
final Collection<LoanTransactionData> transactions = null;
|
||||
@@ -743,7 +752,7 @@ public class LoanAccountData {
|
||||
interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions,
|
||||
loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter,
|
||||
notes, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, fixedEmiAmont, outstandingLoanBalance,
|
||||
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges);
|
||||
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -779,7 +788,7 @@ public class LoanAccountData {
|
||||
loanCollateralOptions, calendarOptions, acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, notes,
|
||||
accountLinkingOptions, linkedAccount, disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount,
|
||||
acc.maxOutstandingLoanBalance, emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
||||
acc.graceOnArrearsAgeing, overdueCharges);
|
||||
acc.graceOnArrearsAgeing, overdueCharges, acc.isNPA);
|
||||
}
|
||||
|
||||
public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection<LoanProductData> productOptions,
|
||||
@@ -809,7 +818,8 @@ public class LoanAccountData {
|
||||
acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
|
||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
||||
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges);
|
||||
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
||||
acc.isNPA);
|
||||
}
|
||||
|
||||
public static LoanAccountData associateMemberVariations(final LoanAccountData acc, final Map<Long, Integer> memberLoanCycle) {
|
||||
@@ -865,7 +875,8 @@ public class LoanAccountData {
|
||||
acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
|
||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
||||
acc.emiAmountVariations, memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges);
|
||||
acc.emiAmountVariations, memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
||||
acc.isNPA);
|
||||
}
|
||||
|
||||
private LoanAccountData(
|
||||
@@ -919,7 +930,7 @@ public class LoanAccountData {
|
||||
final Boolean multiDisburseLoan, BigDecimal fixedEmiAmount, final BigDecimal maxOutstandingLoanBalance,
|
||||
final Collection<LoanTermVariationsData> emiAmountVariations, final Map<Long, LoanBorrowerCycleData> memberVariations,
|
||||
final LoanProductData product, final Boolean inArrears, final Integer graceOnArrearsAgeing,
|
||||
final Collection<ChargeData> overdueCharges) {
|
||||
final Collection<ChargeData> overdueCharges, final Boolean isNPA) {
|
||||
this.id = id;
|
||||
this.accountNo = accountNo;
|
||||
this.status = status;
|
||||
@@ -1057,6 +1068,7 @@ public class LoanAccountData {
|
||||
this.inArrears = inArrears;
|
||||
this.graceOnArrearsAgeing = graceOnArrearsAgeing;
|
||||
this.overdueCharges = overdueCharges;
|
||||
this.isNPA = isNPA;
|
||||
}
|
||||
|
||||
public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() {
|
||||
|
||||
+5
-3
@@ -487,7 +487,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
+ " la.total_overdue_derived as totalOverdue,"
|
||||
+ " la.overdue_since_date_derived as overdueSinceDate,"
|
||||
+ " l.sync_disbursement_with_meeting as syncDisbursementWithMeeting,"
|
||||
+ " l.loan_counter as loanCounter, l.loan_product_counter as loanProductCounter"
|
||||
+ " l.loan_counter as loanCounter, l.loan_product_counter as loanProductCounter,"
|
||||
+ " l.is_npa as isNPA "
|
||||
+ " from m_loan l" //
|
||||
+ " join m_product_loan lp on lp.id = l.product_id" //
|
||||
+ " join m_currency rc on rc.`code` = l.currency_code" //
|
||||
@@ -709,6 +710,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final Integer loanCounter = JdbcSupport.getInteger(rs, "loanCounter");
|
||||
final Integer loanProductCounter = JdbcSupport.getInteger(rs, "loanProductCounter");
|
||||
final BigDecimal fixedEmiAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "fixedEmiAmount");
|
||||
final Boolean isNPA = rs.getBoolean("isNPA");
|
||||
|
||||
return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, groupData,
|
||||
loanType, loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName,
|
||||
@@ -718,7 +720,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
annualInterestRate, interestType, interestCalculationPeriodType, expectedFirstRepaymentOnDate, graceOnPrincipalPayment,
|
||||
graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, timeline, loanSummary,
|
||||
feeChargesDueAtDisbursementCharged, syncDisbursementWithMeeting, loanCounter, loanProductCounter, multiDisburseLoan,
|
||||
fixedEmiAmount, outstandingLoanBalance, inArrears, graceOnArrearsAgeing);
|
||||
fixedEmiAmount, outstandingLoanBalance, inArrears, graceOnArrearsAgeing, isNPA);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1319,7 +1321,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
.append(" where ((if(ls.fee_charges_waived_derived is null , ls.fee_charges_amount,(ls.fee_charges_amount-ls.fee_charges_waived_derived)) <> if(ls.accrual_fee_charges_derived is null,0, ls.accrual_fee_charges_derived))")
|
||||
.append(" or (if(ls.penalty_charges_waived_derived is null , ls.penalty_charges_amount,(ls.penalty_charges_amount-ls.penalty_charges_waived_derived)) <> if(ls.accrual_penalty_charges_derived is null,0,ls.accrual_penalty_charges_derived))")
|
||||
.append(" or (if(ls.interest_waived_derived is null , ls.interest_amount,(ls.interest_amount-ls.interest_waived_derived)) <> if(ls.accrual_interest_derived is null,0,ls.accrual_interest_derived)))")
|
||||
.append(" and loan.loan_status_id=? and mpl.accounting_type=?");
|
||||
.append(" and loan.loan_status_id=? and mpl.accounting_type=? and loan.is_npa=0");
|
||||
return this.jdbcTemplate.query(sqlBuilder.toString(), mapper, new Object[] { LoanStatus.ACTIVE.getValue(),
|
||||
AccountingRuleType.ACCRUAL_PERIODIC.getValue() });
|
||||
}
|
||||
|
||||
+2
@@ -54,5 +54,7 @@ public interface LoanProductConstants {
|
||||
public static final String outstandingLoanBalanceParameterName = "outstandingLoanBalance";
|
||||
|
||||
public static final String graceOnArrearsAgeingParameterName = "graceOnArrearsAgeing";
|
||||
|
||||
public static final String overdueDaysForNPAParameterName = "overdueDaysForNPA";
|
||||
|
||||
}
|
||||
|
||||
+14
-9
@@ -72,6 +72,7 @@ public class LoanProductData {
|
||||
private final Integer graceOnInterestPayment;
|
||||
private final Integer graceOnInterestCharged;
|
||||
private final Integer graceOnArrearsAgeing;
|
||||
private final Integer overdueDaysForNPA;
|
||||
|
||||
// charges
|
||||
private final Collection<ChargeData> charges;
|
||||
@@ -144,6 +145,7 @@ public class LoanProductData {
|
||||
final Integer graceOnInterestPayment = null;
|
||||
final Integer graceOnInterestCharged = null;
|
||||
final Integer graceOnArrearsAgeing = null;
|
||||
final Integer overdueDaysForNPA = null;
|
||||
final Collection<ChargeData> charges = null;
|
||||
final Collection<LoanProductBorrowerCycleVariationData> principalVariations = new ArrayList<LoanProductBorrowerCycleVariationData>(
|
||||
1);
|
||||
@@ -168,7 +170,7 @@ public class LoanProductData {
|
||||
transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges,
|
||||
accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations,
|
||||
interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
|
||||
graceOnArrearsAgeing);
|
||||
graceOnArrearsAgeing, overdueDaysForNPA);
|
||||
}
|
||||
|
||||
public static LoanProductData lookupWithCurrency(final Long id, final String name, final CurrencyData currency) {
|
||||
@@ -199,6 +201,7 @@ public class LoanProductData {
|
||||
final Integer graceOnInterestPayment = null;
|
||||
final Integer graceOnInterestCharged = null;
|
||||
final Integer graceOnArrearsAgeing = null;
|
||||
final Integer overdueDaysForNPA = null;
|
||||
|
||||
final Collection<ChargeData> charges = null;
|
||||
final EnumOptionData accountingType = null;
|
||||
@@ -226,7 +229,7 @@ public class LoanProductData {
|
||||
transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges,
|
||||
accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations,
|
||||
interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
|
||||
graceOnArrearsAgeing);
|
||||
graceOnArrearsAgeing, overdueDaysForNPA);
|
||||
}
|
||||
|
||||
public static LoanProductData sensibleDefaultsForNewLoanProductCreation() {
|
||||
@@ -263,6 +266,7 @@ public class LoanProductData {
|
||||
final Integer graceOnInterestPayment = null;
|
||||
final Integer graceOnInterestCharged = null;
|
||||
final Integer graceOnArrearsAgeing = null;
|
||||
final Integer overdueDaysForNPA = null;
|
||||
|
||||
final Collection<ChargeData> charges = null;
|
||||
final Collection<LoanProductBorrowerCycleVariationData> principalVariationsForBorrowerCycle = new ArrayList<LoanProductBorrowerCycleVariationData>(
|
||||
@@ -290,7 +294,7 @@ public class LoanProductData {
|
||||
transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges,
|
||||
accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId,
|
||||
principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle,
|
||||
multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, graceOnArrearsAgeing);
|
||||
multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA);
|
||||
}
|
||||
|
||||
public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings,
|
||||
@@ -318,7 +322,7 @@ public class LoanProductData {
|
||||
Collection<LoanProductBorrowerCycleVariationData> principalVariations,
|
||||
Collection<LoanProductBorrowerCycleVariationData> interestRateVariations,
|
||||
Collection<LoanProductBorrowerCycleVariationData> numberOfRepaymentVariations, Boolean multiDisburseLoan,
|
||||
Integer maxTrancheCount, BigDecimal outstandingLoanBalance, final Integer graceOnArrearsAgeing) {
|
||||
Integer maxTrancheCount, BigDecimal outstandingLoanBalance, final Integer graceOnArrearsAgeing, final Integer overdueDaysForNPA) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.shortName = shortName;
|
||||
@@ -383,6 +387,7 @@ public class LoanProductData {
|
||||
this.outstandingLoanBalance = outstandingLoanBalance;
|
||||
this.maxTrancheCount = maxTrancheCount;
|
||||
this.graceOnArrearsAgeing = graceOnArrearsAgeing;
|
||||
this.overdueDaysForNPA = overdueDaysForNPA;
|
||||
}
|
||||
|
||||
public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
|
||||
@@ -469,6 +474,7 @@ public class LoanProductData {
|
||||
this.accountingRuleOptions = accountingRuleOptions;
|
||||
this.valueConditionTypeOptions = valueConditionTypeOptions;
|
||||
this.graceOnArrearsAgeing = productData.graceOnArrearsAgeing;
|
||||
this.overdueDaysForNPA = productData.overdueDaysForNPA;
|
||||
|
||||
}
|
||||
|
||||
@@ -655,16 +661,15 @@ public class LoanProductData {
|
||||
return this.outstandingLoanBalance;
|
||||
}
|
||||
|
||||
|
||||
public Integer getGraceOnArrearsAgeing() {
|
||||
return this.graceOnArrearsAgeing;
|
||||
}
|
||||
|
||||
public Collection<ChargeData> overdueFeeCharges(){
|
||||
|
||||
public Collection<ChargeData> overdueFeeCharges() {
|
||||
Collection<ChargeData> overdueFeeCharges = new ArrayList<ChargeData>();
|
||||
Collection<ChargeData> charges = charges();
|
||||
for(ChargeData chargeData : charges){
|
||||
if(chargeData.isOverdueInstallmentCharge()){
|
||||
for (ChargeData chargeData : charges) {
|
||||
if (chargeData.isOverdueInstallmentCharge()) {
|
||||
overdueFeeCharges.add(chargeData);
|
||||
}
|
||||
}
|
||||
|
||||
+16
-2
@@ -116,6 +116,9 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loanProduct", orphanRemoval = true)
|
||||
private Set<LoanProductBorrowerCycleVariations> borrowerCycleVariations = new HashSet<LoanProductBorrowerCycleVariations>();
|
||||
|
||||
@Column(name = "overdue_days_for_npa", nullable = true)
|
||||
private Integer overdueDaysForNPA;
|
||||
|
||||
public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy,
|
||||
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator) {
|
||||
|
||||
@@ -180,13 +183,15 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
|
||||
final Integer graceOnArrearsAgeing = command.integerValueOfParameterNamed(LoanProductConstants.graceOnArrearsAgeingParameterName);
|
||||
|
||||
final Integer overdueDaysForNPA = command.integerValueOfParameterNamed(LoanProductConstants.overdueDaysForNPAParameterName);
|
||||
|
||||
return new LoanProduct(fund, loanTransactionProcessingStrategy, name, shortName, description, currency, principal, minPrincipal,
|
||||
maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType,
|
||||
annualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentFrequencyType,
|
||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, graceOnPrincipalPayment, graceOnInterestPayment,
|
||||
graceOnInterestCharged, amortizationMethod, inArrearsTolerance, productCharges, accountingRuleType, includeInBorrowerCycle,
|
||||
startDate, closeDate, externalId, useBorrowerCycle, loanProductBorrowerCycleVariations, multiDisburseLoan, maxTrancheCount,
|
||||
outstandingLoanBalance, graceOnArrearsAgeing);
|
||||
outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -396,7 +401,8 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
final AccountingRuleType accountingRuleType, final boolean includeInBorrowerCycle, final LocalDate startDate,
|
||||
final LocalDate closeDate, final String externalId, final boolean useBorrowerCycle,
|
||||
final Set<LoanProductBorrowerCycleVariations> loanProductBorrowerCycleVariations, final boolean multiDisburseLoan,
|
||||
final Integer maxTrancheCount, final BigDecimal outstandingLoanBalance, final Integer graceOnArrearsAgeing) {
|
||||
final Integer maxTrancheCount, final BigDecimal outstandingLoanBalance, final Integer graceOnArrearsAgeing,
|
||||
final Integer overdueDaysForNPA) {
|
||||
this.fund = fund;
|
||||
this.transactionProcessingStrategy = transactionProcessingStrategy;
|
||||
this.name = name.trim();
|
||||
@@ -442,6 +448,7 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
borrowerCycleVariations.updateLoanProduct(this);
|
||||
}
|
||||
this.loanProducTrancheDetails = new LoanProductTrancheDetails(multiDisburseLoan, maxTrancheCount, outstandingLoanBalance);
|
||||
this.overdueDaysForNPA = overdueDaysForNPA;
|
||||
}
|
||||
|
||||
public MonetaryCurrency getCurrency() {
|
||||
@@ -606,6 +613,13 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
}
|
||||
loanProducTrancheDetails.update(command, actualChanges, localeAsInput);
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.overdueDaysForNPAParameterName, this.overdueDaysForNPA)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.overdueDaysForNPAParameterName);
|
||||
actualChanges.put(LoanProductConstants.overdueDaysForNPAParameterName, newValue);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.overdueDaysForNPA = newValue;
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
|
||||
+16
-3
@@ -60,7 +60,8 @@ public final class LoanProductDataValidator {
|
||||
LoanProductConstants.interestRateVariationsForBorrowerCycleParameterName,
|
||||
LoanProductConstants.numberOfRepaymentVariationsForBorrowerCycleParameterName, LoanProductConstants.shortName,
|
||||
LoanProductConstants.multiDisburseLoanParameterName, LoanProductConstants.outstandingLoanBalanceParameterName,
|
||||
LoanProductConstants.maxTrancheCountParameterName, LoanProductConstants.graceOnArrearsAgeingParameterName));
|
||||
LoanProductConstants.maxTrancheCountParameterName, LoanProductConstants.graceOnArrearsAgeingParameterName,
|
||||
LoanProductConstants.overdueDaysForNPAParameterName));
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@@ -255,7 +256,12 @@ public final class LoanProductDataValidator {
|
||||
final Integer graceOnArrearsAgeing = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
||||
LoanProductConstants.graceOnArrearsAgeingParameterName, element);
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.graceOnArrearsAgeingParameterName).value(graceOnArrearsAgeing)
|
||||
.zeroOrPositiveAmount();
|
||||
.integerZeroOrGreater();
|
||||
|
||||
final Integer overdueDaysForNPA = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
||||
LoanProductConstants.overdueDaysForNPAParameterName, element);
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.overdueDaysForNPAParameterName).value(overdueDaysForNPA)
|
||||
.integerZeroOrGreater();
|
||||
|
||||
// accounting related data validation
|
||||
final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
|
||||
@@ -528,7 +534,14 @@ public final class LoanProductDataValidator {
|
||||
final Integer graceOnArrearsAgeing = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
||||
LoanProductConstants.graceOnArrearsAgeingParameterName, element);
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.graceOnArrearsAgeingParameterName).value(graceOnArrearsAgeing)
|
||||
.zeroOrPositiveAmount();
|
||||
.integerZeroOrGreater();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.overdueDaysForNPAParameterName, element)) {
|
||||
final Integer overdueDaysForNPA = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
||||
LoanProductConstants.overdueDaysForNPAParameterName, element);
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.overdueDaysForNPAParameterName).value(overdueDaysForNPA)
|
||||
.integerZeroOrGreater();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
+4
-2
@@ -117,7 +117,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
+ "lp.nominal_interest_rate_per_period as interestRatePerPeriod, lp.min_nominal_interest_rate_per_period as minInterestRatePerPeriod, lp.max_nominal_interest_rate_per_period as maxInterestRatePerPeriod, lp.interest_period_frequency_enum as interestRatePerPeriodFreq, "
|
||||
+ "lp.annual_nominal_interest_rate as annualInterestRate, lp.interest_method_enum as interestMethod, lp.interest_calculated_in_period_enum as interestCalculationInPeriodMethod,"
|
||||
+ "lp.repay_every as repaidEvery, lp.repayment_period_frequency_enum as repaymentPeriodFrequency, lp.number_of_repayments as numberOfRepayments, lp.min_number_of_repayments as minNumberOfRepayments, lp.max_number_of_repayments as maxNumberOfRepayments, "
|
||||
+ "lp.grace_on_principal_periods as graceOnPrincipalPayment, lp.grace_on_interest_periods as graceOnInterestPayment, lp.grace_interest_free_periods as graceOnInterestCharged,lp.grace_on_arrears_ageing as graceOnArrearsAgeing, "
|
||||
+ "lp.grace_on_principal_periods as graceOnPrincipalPayment, lp.grace_on_interest_periods as graceOnInterestPayment, lp.grace_interest_free_periods as graceOnInterestCharged,lp.grace_on_arrears_ageing as graceOnArrearsAgeing,lp.overdue_days_for_npa as overdueDaysForNPA, "
|
||||
+ "lp.amortization_method_enum as amortizationMethod, lp.arrearstolerance_amount as tolerance, "
|
||||
+ "lp.accounting_type as accountingType, lp.include_in_borrower_cycle as includeInBorrowerCycle,lp.use_borrower_cycle as useBorrowerCycle, lp.start_date as startDate, lp.close_date as closeDate, "
|
||||
+ "lp.allow_multiple_disbursals as multiDisburseLoan, lp.max_disbursals as maxTrancheCount, lp.max_outstanding_loan_balance as outstandingLoanBalance, "
|
||||
@@ -164,6 +164,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
final Integer graceOnInterestPayment = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "graceOnInterestPayment");
|
||||
final Integer graceOnInterestCharged = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "graceOnInterestCharged");
|
||||
final Integer graceOnArrearsAgeing = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "graceOnArrearsAgeing");
|
||||
final Integer overdueDaysForNPA = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "overdueDaysForNPA");
|
||||
|
||||
final Integer accountingRuleId = JdbcSupport.getInteger(rs, "accountingType");
|
||||
final EnumOptionData accountingRuleType = AccountingEnumerations.accountingRuleType(accountingRuleId);
|
||||
@@ -227,7 +228,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
transactionStrategyId, transactionStrategyName, graceOnPrincipalPayment, graceOnInterestPayment,
|
||||
graceOnInterestCharged, this.charges, accountingRuleType, includeInBorrowerCycle, useBorrowerCycle, startDate,
|
||||
closeDate, status, externalId, principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle,
|
||||
numberOfRepaymentVariationsForBorrowerCycle, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, graceOnArrearsAgeing);
|
||||
numberOfRepaymentVariationsForBorrowerCycle, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
|
||||
graceOnArrearsAgeing, overdueDaysForNPA);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -18,4 +18,6 @@ public interface ScheduledJobRunnerService {
|
||||
void applyAnnualFeeForSavings();
|
||||
|
||||
void applyDueChargesForSavings() throws JobExecutionException;
|
||||
|
||||
void updateNPA();
|
||||
}
|
||||
|
||||
+31
-4
@@ -61,8 +61,10 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
|
||||
updateSqlBuilder.append("SUM(IFNULL(mr.interest_completed_derived,0)) as interest_repaid_derived,");
|
||||
updateSqlBuilder.append("SUM(IFNULL(mr.interest_waived_derived,0)) as interest_waived_derived,");
|
||||
updateSqlBuilder.append("SUM(IFNULL(mr.interest_writtenoff_derived,0)) as interest_writtenoff_derived,");
|
||||
updateSqlBuilder.append("SUM(IFNULL(mr.fee_charges_amount,0)) + IFNULL((select SUM(lc.amount) from m_loan_charge lc where lc.loan_id=ml.id and lc.is_active=1 and lc.charge_id=1),0) as fee_charges_charged_derived,");
|
||||
updateSqlBuilder.append("SUM(IFNULL(mr.fee_charges_completed_derived,0)) + IFNULL((select SUM(lc.amount_paid_derived) from m_loan_charge lc where lc.loan_id=ml.id and lc.is_active=1 and lc.charge_id=1),0) as fee_charges_repaid_derived,");
|
||||
updateSqlBuilder
|
||||
.append("SUM(IFNULL(mr.fee_charges_amount,0)) + IFNULL((select SUM(lc.amount) from m_loan_charge lc where lc.loan_id=ml.id and lc.is_active=1 and lc.charge_id=1),0) as fee_charges_charged_derived,");
|
||||
updateSqlBuilder
|
||||
.append("SUM(IFNULL(mr.fee_charges_completed_derived,0)) + IFNULL((select SUM(lc.amount_paid_derived) from m_loan_charge lc where lc.loan_id=ml.id and lc.is_active=1 and lc.charge_id=1),0) as fee_charges_repaid_derived,");
|
||||
updateSqlBuilder.append("SUM(IFNULL(mr.fee_charges_waived_derived,0)) as fee_charges_waived_derived,");
|
||||
updateSqlBuilder.append("SUM(IFNULL(mr.fee_charges_writtenoff_derived,0)) as fee_charges_writtenoff_derived,");
|
||||
updateSqlBuilder.append("SUM(IFNULL(mr.penalty_charges_amount,0)) as penalty_charges_charged_derived,");
|
||||
@@ -216,8 +218,8 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
|
||||
logger.error("Apply annual fee failed for account:" + savingsAccountReference.getAccountNo() + " with message "
|
||||
+ error.getDeveloperMessage());
|
||||
}
|
||||
} catch (final Exception ex){
|
||||
//need to handle this scenario
|
||||
} catch (final Exception ex) {
|
||||
// need to handle this scenario
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,4 +256,29 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
|
||||
if (errorMsg.length() > 0) { throw new JobExecutionException(errorMsg.toString()); }
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
@CronTarget(jobName = JobName.UPDATE_NPA)
|
||||
public void updateNPA() {
|
||||
|
||||
final JdbcTemplate jdbcTemplate = new JdbcTemplate(this.dataSourceServiceFactory.determineDataSourceService().retrieveDataSource());
|
||||
|
||||
jdbcTemplate.update("UPDATE m_loan ml SET ml.is_npa=0");
|
||||
|
||||
final StringBuilder updateSqlBuilder = new StringBuilder(900);
|
||||
|
||||
updateSqlBuilder.append("UPDATE m_loan as ml,");
|
||||
updateSqlBuilder.append(" (select loan.id from m_loan_repayment_schedule mr ");
|
||||
updateSqlBuilder
|
||||
.append(" INNER JOIN m_loan loan on mr.loan_id = loan.id INNER JOIN m_product_loan mpl on mpl.id = loan.product_id ");
|
||||
updateSqlBuilder.append("WHERE loan.loan_status_id = 300 and mr.completed_derived is false ");
|
||||
updateSqlBuilder
|
||||
.append(" and mr.duedate < SUBDATE(CURDATE(),INTERVAL ifnull(mpl.overdue_days_for_npa,0) day) group by loan.id) as sl ");
|
||||
updateSqlBuilder.append("SET ml.is_npa=1 where ml.id=sl.id");
|
||||
|
||||
final int result = jdbcTemplate.update(updateSqlBuilder.toString());
|
||||
|
||||
logger.info(ThreadLocalContextUtil.getTenant().getName() + ": Results affected by update: " + result);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user