Merge pull request #423 from mifoscontributer/MIFOSX-212-JLG

Add Loan counter for Group and JLG Loan
This commit is contained in:
Keith Woodlock
2013-07-04 05:13:25 -07:00
12 changed files with 406 additions and 152 deletions
+99 -2
View File
@@ -191,6 +191,22 @@
<td></td> <td></td>
<td></td> <td></td>
</tr> </tr>
<tr class="alt">
<td></td>
<td>clients/{clientId}?command=assignStaff</td>
<td><a href="#clients_assignStaff">Assign Staff</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>clients/{clientId}?command=unassignStaff</td>
<td><a href="#clients_unassignStaff">Unassign Staff</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr class="alt"> <tr class="alt">
<td></td> <td></td>
<td>clients/{clientId}/loans</td> <td>clients/{clientId}/loans</td>
@@ -1818,6 +1834,12 @@ function executeAjaxRequest(url, verbType, jsonData, basicAuthKey, successFuncti
business that doesnt suit the firstname,middlename,lastname business that doesnt suit the firstname,middlename,lastname
structure.</td> structure.</td>
</tr> </tr>
<tr class=alt>
<td>staffId</td>
</tr>
<tr>
<td class=fielddesc>The staffId of the staff member dealing with the client office. The staff member is not specifically the loan officer.</td>
</tr>
</table> </table>
</div> </div>
</div> </div>
@@ -1906,7 +1928,7 @@ GET https://DomainName/api/v1/clients/template
<td><div class="mifosXHeading2">Optional Fields</div></td> <td><div class="mifosXHeading2">Optional Fields</div></td>
</tr> </tr>
<tr class=alt> <tr class=alt>
<td>groupId, externalId, accountNo</td> <td>groupId, externalId, accountNo, staffId</td>
</tr> </tr>
</table> </table>
</div> </div>
@@ -2017,6 +2039,59 @@ Request Body:
</code> </code>
</div> </div>
</div> </div>
<a id="clients_assignStaff" name="clients_assignStaff" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Assign a Staff</h4>
<p>Allows you to assign <i>Staff</i> for existed Client.</p>
<p>The selected Staff member should be belongs to the client's office.</p>
</div>
<div class="method-example">
<code class="method-declaration">POST https://Domain Name/api/v1/clients/{clientId}?command=assignStaff</code>
<code class="method-request">POST clients/1?command=assignStaff
Content-Type: application/json
Request Body:
{
"staffId": "1"
}
</code>
<code class="method-response">
{
"officeId": 1,
"clientId": 1,
"resourceId": 1,
"changes": {"staffId":1}
}
</code>
</div>
</div>
<a id="clients_unassignStaff" name="clients_unassignStaff" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Unassign a Staff</h4>
<p>Allows you to unassign the <i>Staff</i>.</p>
</div>
<div class="method-example">
<code class="method-declaration">POST https://Domain Name/api/v1/clients/{clientId}?command=unassignStaff</code>
<code class="method-request">POST clients/1?command=unassignStaff
Content-Type: application/json
Request Body:
{
"staffId":"1"
}
</code>
<code class="method-response">
{
"officeId": 1,
"clientId": 1,
"resourceId": 1,
"changes": {"staffId":1}
}
</code>
</div>
</div>
<a id="clients_retrieve" name="clients_retrieve" class="old-syle-anchor">&nbsp;</a> <a id="clients_retrieve" name="clients_retrieve" class="old-syle-anchor">&nbsp;</a>
<div class="method-section"> <div class="method-section">
<div class="method-description"> <div class="method-description">
@@ -7084,6 +7159,12 @@ Request Body:
<tr> <tr>
<td class=fielddesc>For associating a loan product with a given fund by default.</td> <td class=fielddesc>For associating a loan product with a given fund by default.</td>
</tr> </tr>
<tr class=alt>
<td>includeInBorrowerCycle</td>
</tr>
<tr>
<td class=fielddesc>It is a flag, Used to denote whether the loans should include in loan cycle counter or not.</td>
</tr>
<tr class=alt> <tr class=alt>
<td>currencyCode</td> <td>currencyCode</td>
</tr> </tr>
@@ -7786,7 +7867,7 @@ GET https://DomainName/api/v1/loanproducts/{productId}
<td><div class="mifosXHeading2">Optional Fields</div></td> <td><div class="mifosXHeading2">Optional Fields</div></td>
</tr> </tr>
<tr class=alt> <tr class=alt>
<td>inArrearsTolerance, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges, paymentChannelToFundSourceMappings, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings</td> <td>inArrearsTolerance, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges, paymentChannelToFundSourceMappings, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, includeInBorrowerCycle</td>
</tr> </tr>
<tr class="matrixHeadingBG"> <tr class="matrixHeadingBG">
@@ -15834,6 +15915,22 @@ GET https://DomainName/api/v1/search?query=000000111
<td></td> <td></td>
<td></td> <td></td>
</tr> </tr>
<tr class="alt">
<td></td>
<td>clients/{clientId}?command=assignStaff</td>
<td><a href="#clients_assignStaff">Assign Staff</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>clients/{clientId}?command=unassignStaff</td>
<td><a href="#clients_unassignStaff">Unassign Staff</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr class="alt"> <tr class="alt">
<td></td> <td></td>
<td>clients/{clientId}/loans</td> <td>clients/{clientId}/loans</td>
@@ -0,0 +1,15 @@
ALTER TABLE `m_client_loan_counter`
ADD COLUMN `group_id` BIGINT(20) NOT NULL AFTER `client_id`,
ADD CONSTRAINT `FK_m_group_loan_counter` FOREIGN KEY (`group_id`) REFERENCES `m_group` (`id`);
RENAME TABLE `m_client_loan_counter` TO `m_loan_counter`;
ALTER TABLE `m_loan_counter`
CHANGE COLUMN `client_id` `client_id` BIGINT(20) NULL DEFAULT NULL AFTER `id`,
CHANGE COLUMN `group_id` `group_id` BIGINT(20) NULL DEFAULT NULL AFTER `client_id`;
ALTER TABLE `m_loan`
ADD COLUMN `loan_counter` SMALLINT NULL DEFAULT NULL AFTER `sync_disbursement_with_meeting`,
ADD COLUMN `loan_product_counter` SMALLINT NULL DEFAULT NULL AFTER `loan_counter`;
DROP TABLE `m_loan_counter`;
@@ -521,9 +521,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
StringBuilder accountsSummary = new StringBuilder("l.id as id, l.account_no as accountNo, l.external_id as externalId,"); StringBuilder accountsSummary = new StringBuilder("l.id as id, l.account_no as accountNo, l.external_id as externalId,");
accountsSummary.append("l.product_id as productId, lp.name as productName,") accountsSummary.append("l.product_id as productId, lp.name as productName,")
.append("l.loan_status_id as statusId, l.loan_type_enum as loanType, ") .append("l.loan_status_id as statusId, l.loan_type_enum as loanType, ")
.append("lc.running_count as loanCycle ").append(" from m_loan l ") .append("l.loan_product_counter as loanCycle ").append(" from m_loan l ")
.append("LEFT JOIN m_product_loan AS lp ON lp.id = l.product_id ") .append("LEFT JOIN m_product_loan AS lp ON lp.id = l.product_id");
.append("LEFT JOIN m_client_loan_counter lc on l.id = lc.loan_id ");
return accountsSummary.toString(); return accountsSummary.toString();
} }
@@ -96,7 +96,8 @@ public class LoansApiResource {
"summary", "repaymentSchedule", "transactions", "charges", "collateral", "guarantors", "meeting", "productOptions", "summary", "repaymentSchedule", "transactions", "charges", "collateral", "guarantors", "meeting", "productOptions",
"amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", "repaymentFrequencyTypeOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", "repaymentFrequencyTypeOptions",
"termFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "repaymentStrategyOptions", "chargeOptions", "termFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "repaymentStrategyOptions", "chargeOptions",
"loanOfficerOptions", "loanPurposeOptions", "loanCollateralOptions", "chargeTemplate", "calendarOptions", "syncDisbursementWithMeeting")); "loanOfficerOptions", "loanPurposeOptions", "loanCollateralOptions", "chargeTemplate", "calendarOptions", "syncDisbursementWithMeeting",
"loanCounter", "loanProductCounter"));
private final String resourceNameForPermissions = "LOAN"; private final String resourceNameForPermissions = "LOAN";
@@ -123,6 +123,10 @@ public class LoanAccountData {
private final BigDecimal feeChargesAtDisbursementCharged; private final BigDecimal feeChargesAtDisbursementCharged;
private final BigDecimal totalOverpaid; private final BigDecimal totalOverpaid;
//loanCycle
private final Integer loanCounter;
private final Integer loanProductCounter;
/** /**
* Used to produce a {@link LoanAccountData} with only collateral options * Used to produce a {@link LoanAccountData} with only collateral options
* for now. * for now.
@@ -192,6 +196,8 @@ public class LoanAccountData {
final Collection<CodeValueData> loanPurposeOptions = null; final Collection<CodeValueData> loanPurposeOptions = null;
final Collection<CalendarData> calendarOptions = null; final Collection<CalendarData> calendarOptions = null;
final Boolean syncDisbursementWithMeeting = null; final Boolean syncDisbursementWithMeeting = null;
final Integer loancounter = null;
final Integer loanProductCounter = null;
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId, return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
@@ -203,7 +209,7 @@ public class LoanAccountData {
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, transactionProcessingStrategyOptions, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, transactionProcessingStrategyOptions,
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
syncDisbursementWithMeeting); syncDisbursementWithMeeting, loancounter, loanProductCounter);
} }
/** /**
@@ -275,6 +281,8 @@ public class LoanAccountData {
final Collection<CodeValueData> loanCollateralOptions = null; final Collection<CodeValueData> loanCollateralOptions = null;
final Collection<CalendarData> calendarOptions = null; final Collection<CalendarData> calendarOptions = null;
final Boolean syncDisbursementWithMeeting = null; final Boolean syncDisbursementWithMeeting = null;
final Integer loancounter = null;
final Integer loanProductCounter = null;
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId, return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
@@ -285,7 +293,8 @@ public class LoanAccountData {
feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors, calendarData,
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions,
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting); fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
syncDisbursementWithMeeting, loancounter, loanProductCounter);
} }
public static LoanAccountData populateClientDefaults(final LoanAccountData acc, final LoanAccountData clientAcc) { public static LoanAccountData populateClientDefaults(final LoanAccountData acc, final LoanAccountData clientAcc) {
@@ -302,7 +311,8 @@ public class LoanAccountData {
acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions,
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.syncDisbursementWithMeeting); acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.syncDisbursementWithMeeting,
acc.loanCounter, acc.loanProductCounter);
} }
/** /**
@@ -375,6 +385,8 @@ public class LoanAccountData {
final Collection<CodeValueData> loanCollateralOptions = null; final Collection<CodeValueData> loanCollateralOptions = null;
final Collection<CalendarData> calendarOptions = null; final Collection<CalendarData> calendarOptions = null;
final Boolean syncDisbursementWithMeeting = null; final Boolean syncDisbursementWithMeeting = null;
final Integer loancounter = null;
final Integer loanProductCounter = null;
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId, return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
@@ -386,7 +398,7 @@ public class LoanAccountData {
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions,
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
syncDisbursementWithMeeting); syncDisbursementWithMeeting, loancounter, loanProductCounter);
} }
public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) { public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) {
@@ -404,7 +416,7 @@ public class LoanAccountData {
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
acc.syncDisbursementWithMeeting); acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter);
} }
public static LoanAccountData loanProductWithTemplateDefaults(final LoanProductData product, public static LoanAccountData loanProductWithTemplateDefaults(final LoanProductData product,
@@ -470,6 +482,9 @@ public class LoanAccountData {
charges.add(charge.toLoanChargeData()); charges.add(charge.toLoanChargeData());
} }
final Integer loancounter = null;
final Integer loanProductCounter = null;
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType,
product.getId(), product.getName(), product.getDescription(), product.getFundId(), product.getFundName(), loanPurposeId, product.getId(), product.getName(), product.getDescription(), product.getFundId(), product.getFundName(), loanPurposeId,
loanPurposeName, loanOfficerId, loanOfficerName, product.getCurrency(), product.getPrincipal(), totalOverpaid, loanPurposeName, loanOfficerId, loanOfficerName, product.getCurrency(), product.getPrincipal(), totalOverpaid,
@@ -482,7 +497,7 @@ public class LoanAccountData {
repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions,
repaymentFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions,
interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions,
loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting); loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter);
} }
public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) { public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) {
@@ -528,7 +543,8 @@ public class LoanAccountData {
acc.summary, acc.feeChargesAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors, acc.summary, acc.feeChargesAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors,
calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions,
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, acc.syncDisbursementWithMeeting); fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter);
} }
/* /*
@@ -547,7 +563,8 @@ public class LoanAccountData {
final EnumOptionData interestCalculationPeriodType, final LocalDate expectedFirstRepaymentOnDate, final EnumOptionData interestCalculationPeriodType, final LocalDate expectedFirstRepaymentOnDate,
final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged,
final LocalDate interestChargedFromDate, final LoanApplicationTimelineData timeline, final LoanSummaryData loanSummary, final LocalDate interestChargedFromDate, final LoanApplicationTimelineData timeline, final LoanSummaryData loanSummary,
final BigDecimal feeChargesDueAtDisbursementCharged, final Boolean syncDisbursementWithMeeting) { final BigDecimal feeChargesDueAtDisbursementCharged, final Boolean syncDisbursementWithMeeting,
final Integer loancounter, final Integer loanProductCounter) {
final LoanScheduleData repaymentSchedule = null; final LoanScheduleData repaymentSchedule = null;
final Collection<LoanTransactionData> transactions = null; final Collection<LoanTransactionData> transactions = null;
@@ -581,7 +598,7 @@ public class LoanAccountData {
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions,
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
syncDisbursementWithMeeting); syncDisbursementWithMeeting, loancounter, loanProductCounter);
} }
/* /*
@@ -611,7 +628,7 @@ public class LoanAccountData {
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, transactionProcessingStrategyOptions, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, transactionProcessingStrategyOptions,
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
acc.syncDisbursementWithMeeting); acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter);
} }
public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection<LoanProductData> productOptions, public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection<LoanProductData> productOptions,
@@ -637,7 +654,7 @@ public class LoanAccountData {
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
acc.syncDisbursementWithMeeting); acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter);
} }
private LoanAccountData( private LoanAccountData(
@@ -684,7 +701,7 @@ public class LoanAccountData {
final Collection<FundData> fundOptions, final Collection<ChargeData> chargeOptions, final ChargeData chargeTemplate, final Collection<FundData> fundOptions, final Collection<ChargeData> chargeOptions, final ChargeData chargeTemplate,
final Collection<StaffData> loanOfficerOptions, final Collection<CodeValueData> loanPurposeOptions, final Collection<StaffData> loanOfficerOptions, final Collection<CodeValueData> loanPurposeOptions,
final Collection<CodeValueData> loanCollateralOptions, final Collection<CalendarData> calendarOptions, final Collection<CodeValueData> loanCollateralOptions, final Collection<CalendarData> calendarOptions,
final Boolean syncDisbursementWithMeeting) { final Boolean syncDisbursementWithMeeting, final Integer loanCounter, final Integer loanProductCounter) {
this.id = id; this.id = id;
this.accountNo = accountNo; this.accountNo = accountNo;
this.status = status; this.status = status;
@@ -789,6 +806,9 @@ public class LoanAccountData {
} else { } else {
this.calendarOptions = calendarOptions; this.calendarOptions = calendarOptions;
} }
this.loanCounter = loanCounter;
this.loanProductCounter = loanProductCounter;
} }
public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() { public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() {
@@ -100,7 +100,6 @@ public class Loan extends AbstractPersistable<Long> {
@JoinColumn(name = "group_id", nullable = true) @JoinColumn(name = "group_id", nullable = true)
private Group group; private Group group;
@SuppressWarnings("unused")
@Column(name = "loan_type_enum", nullable = false) @Column(name = "loan_type_enum", nullable = false)
private Integer loanType; private Integer loanType;
@@ -231,6 +230,12 @@ public class Loan extends AbstractPersistable<Long> {
@Column(name = "total_overpaid_derived", scale = 6, precision = 19) @Column(name = "total_overpaid_derived", scale = 6, precision = 19)
private BigDecimal totalOverpaid; private BigDecimal totalOverpaid;
@Column(name = "loan_counter")
private Integer loanCounter;
@Column(name = "loan_product_counter")
private Integer loanProductCounter;
@LazyCollection(LazyCollectionOption.FALSE) @LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true) @OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true)
private Set<LoanCharge> charges = new HashSet<LoanCharge>(); private Set<LoanCharge> charges = new HashSet<LoanCharge>();
@@ -2349,4 +2354,28 @@ public class Loan extends AbstractPersistable<Long> {
} }
} }
public Group group() {
return this.group;
}
public Integer getCurrentLoanCounter() {
return this.loanCounter;
}
public Integer getLoanProductLoanCounter() {
return this.loanProductCounter;
}
public void updateClientLoanCounter(Integer newLoanCounter) {
this.loanCounter = newLoanCounter;
}
public void updateLoanProductLoanCounter(Integer newLoanProductLoanCounter) {
this.loanProductCounter = newLoanProductLoanCounter;
}
public boolean isGroupLoan() {
return LoanType.fromInt(this.loanType).isGroupLoan();
}
} }
@@ -1,60 +0,0 @@
package org.mifosplatform.portfolio.loanaccount.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity
@Table(name = "m_client_loan_counter")
public class LoanCycle extends AbstractPersistable<Long> {
@ManyToOne
@JoinColumn(name = "client_id", nullable = false)
private Client client;
@ManyToOne
@JoinColumn(name = "loan_product_id", nullable = false)
private LoanProduct loanProduct;
@ManyToOne
@JoinColumn(name = "loan_id", nullable = false)
private Loan loan;
@Column(name = "running_count", nullable = false)
private Integer runningCount;
public LoanCycle() {
}
private LoanCycle(final Client client, final LoanProduct loanProduct, final Loan loan, final Integer runningCounter) {
this.client = client;
this.loanProduct = loanProduct;
this.loan = loan;
this.runningCount = runningCounter;
}
public static LoanCycle create(final Client client, final LoanProduct loanProduct, final Loan loan, final Integer runningCounter) {
return new LoanCycle(client, loanProduct, loan, runningCounter);
}
public Integer getRunningCounter() {
return this.runningCount;
}
public Loan loan() {
return this.loan;
}
public LoanCycle updateLoanCycleCounter(final Integer runningCount) {
this.runningCount = runningCount;
return this;
}
}
@@ -1,15 +0,0 @@
package org.mifosplatform.portfolio.loanaccount.domain;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface LoanCycleRepository extends JpaRepository<LoanCycle, Long>, JpaSpecificationExecutor<LoanCycle> {
@Query("from LoanCycle lc where lc.client.id=:clientId and lc.loanProduct.id=:loanProductId order by lc.runningCount")
List<LoanCycle> findByClientIdAndLoanProductId(@Param("clientId") Long clientId, @Param("loanProductId") Long loanProductId);
}
@@ -14,17 +14,79 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
public interface LoanRepository extends JpaRepository<Loan, Long>, public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificationExecutor<Loan> {
JpaSpecificationExecutor<Loan> {
@Query("from Loan loan where loan.client.id = :clientId and loan.group.id = :groupId")
List<Loan> findByClientIdAndGroupId(@Param("clientId") Long clientId, @Param("groupId") Long groupId);
@Query("from Loan loan where loan.client.id = :clientId") public static final String FIND_GROUP_LOANS_DISBURSED_AFTER = "from Loan l where l.actualDisbursementDate > :disbursementDate and "
List<Loan> findLoanByClientId(@Param("clientId") Long clientId); + "l.group.id = :groupId and l.loanType = :loanType order by l.actualDisbursementDate";
@Query("from Loan loan where loan.id IN :ids and loan.loanStatus IN :loanStatuses and loan.loanType IN :loanTypes") public static final String FIND_CLIENT_OR_JLG_LOANS_DISBURSED_AFTER = "from Loan l where l.actualDisbursementDate > :disbursementDate and "
List<Loan> findByIdsAndLoanStatusAndLoanType(@Param("ids") Collection<Long> ids, @Param("loanStatuses") Collection<Integer> loanStatuses, @Param("loanTypes") Collection<Integer> loanTypes); + "l.client.id = :clientId order by l.actualDisbursementDate";
@Query("select loan.id from Loan loan where loan.actualDisbursementDate > :disbursalDate order by loan.actualDisbursementDate") public static final String FIND_MAX_GROUP_LOAN_COUNTER_QUERY = "Select MAX(l.loanCounter) from Loan l where l.group.id = :groupId "
List<Long> getLoansDisbursedAfter(@Param("disbursalDate") Date disbursalDate); + "and l.loanType = :loanType";
public static final String FIND_MAX_GROUP_LOAN_PRODUCT_COUNTER_QUERY = "Select MAX(l.loanProductCounter) from Loan l where "
+ "l.group.id = :groupId and l.loanType = :loanType and l.loanProduct.id = :productId";
public static final String FIND_MAX_CLIENT_OR_JLG_LOAN_COUNTER_QUERY = "Select MAX(l.loanCounter) from Loan l where "
+ "l.client.id = :clientId";
public static final String FIND_MAX_CLIENT_OR_JLG_LOAN_PRODUCT_COUNTER_QUERY = "Select MAX(l.loanProductCounter) from Loan l where "
+ "l.client.id = :clientId and l.loanProduct.id = :productId";
public static final String FIND_GROUP_LOANS_TO_UPDATE = "from Loan l where l.loanCounter > :loanCounter and "
+ "l.group.id = :groupId and l.loanType = :groupLoanType order by l.loanCounter";
public static final String FIND_CLIENT_OR_JLG_LOANS_TO_UPDATE = "from Loan l where l.loanCounter > :loanCounter and "
+ "l.client.id = :clientId order by l.loanCounter";
public static final String FIND_GROUP_LOANS_TO_UPDATE_LOANPRODUCT_COUNTER = "from Loan l where l.loanProductCounter > :loanProductCounter"
+ " and l.group.id = :groupId and l.loanType = :groupLoanType and l.loanCounter is NULL order by l.loanProductCounter";
public static final String FIND_CLIENT_LOANS_TO_UPDATE_LOANPRODUCT_COUNTER = "from Loan l where l.loanProductCounter > :loanProductCounter"
+ " and l.client.id = :clientId and l.loanCounter is NULL order by l.loanProductCounter";
@Query("from Loan loan where loan.client.id = :clientId and loan.group.id = :groupId")
List<Loan> findByClientIdAndGroupId(@Param("clientId") Long clientId, @Param("groupId") Long groupId);
@Query("from Loan loan where loan.client.id = :clientId")
List<Loan> findLoanByClientId(@Param("clientId") Long clientId);
@Query("from Loan loan where loan.id IN :ids and loan.loanStatus IN :loanStatuses and loan.loanType IN :loanTypes")
List<Loan> findByIdsAndLoanStatusAndLoanType(@Param("ids") Collection<Long> ids,
@Param("loanStatuses") Collection<Integer> loanStatuses, @Param("loanTypes") Collection<Integer> loanTypes);
@Query(FIND_GROUP_LOANS_DISBURSED_AFTER)
List<Loan> getGroupLoansDisbursedAfter(@Param("disbursementDate") Date disbursementDate, @Param("groupId") Long groupId,
@Param("loanType") Integer loanType);
@Query(FIND_CLIENT_OR_JLG_LOANS_DISBURSED_AFTER)
List<Loan> getClientOrJLGLoansDisbursedAfter(@Param("disbursementDate") Date disbursementDate, @Param("clientId") Long clientId);
@Query(FIND_MAX_GROUP_LOAN_COUNTER_QUERY)
Integer getMaxGroupLoanCounter(@Param("groupId") Long groupId, @Param("loanType") Integer loanType);
@Query(FIND_MAX_GROUP_LOAN_PRODUCT_COUNTER_QUERY)
Integer getMaxGroupLoanProductCounter(@Param("productId") Long productId, @Param("groupId") Long groupId,
@Param("loanType") Integer loanType);
@Query(FIND_MAX_CLIENT_OR_JLG_LOAN_COUNTER_QUERY)
Integer getMaxClientOrJLGLoanCounter(@Param("clientId") Long clientId);
@Query(FIND_MAX_CLIENT_OR_JLG_LOAN_PRODUCT_COUNTER_QUERY)
Integer getMaxClientOrJLGLoanProductCounter(@Param("productId") Long productId, @Param("clientId") Long clientId);
@Query(FIND_GROUP_LOANS_TO_UPDATE)
List<Loan> getGroupLoansToUpdateLoanCounter(@Param("loanCounter") Integer loanCounter, @Param("groupId") Long groupId,
@Param("groupLoanType") Integer groupLoanType);
@Query(FIND_CLIENT_OR_JLG_LOANS_TO_UPDATE)
List<Loan> getClientOrJLGLoansToUpdateLoanCounter(@Param("loanCounter") Integer loanCounter, @Param("clientId") Long clientId);
@Query(FIND_GROUP_LOANS_TO_UPDATE_LOANPRODUCT_COUNTER)
List<Loan> getGroupLoansToUpdateLoanProductCounter(@Param("loanProductCounter") Integer loanProductCounter, @Param("groupId") Long groupId,
@Param("groupLoanType") Integer groupLoanType);
@Query(FIND_CLIENT_LOANS_TO_UPDATE_LOANPRODUCT_COUNTER)
List<Loan> getClientLoansToUpdateLoanProductCounter(@Param("loanProductCounter") Integer loanProductCounter, @Param("clientId") Long clientId);
} }
@@ -443,7 +443,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
+ " la.penalty_charges_overdue_derived as penaltyChargesOverdue," + " la.penalty_charges_overdue_derived as penaltyChargesOverdue,"
+ " la.total_overdue_derived as totalOverdue," + " la.total_overdue_derived as totalOverdue,"
+ " la.overdue_since_date_derived as overdueSinceDate," + " la.overdue_since_date_derived as overdueSinceDate,"
+ " l.sync_disbursement_with_meeting as syncDisbursementWithMeeting" + " l.sync_disbursement_with_meeting as syncDisbursementWithMeeting,"
+ " l.loan_counter as loanCounter, l.loan_product_counter as loanProductCounter"
+ " from m_loan l" // + " from m_loan l" //
+ " join m_product_loan lp on lp.id = l.product_id" // + " join m_product_loan lp on lp.id = l.product_id" //
+ " join m_currency rc on rc.`code` = l.currency_code" // + " join m_currency rc on rc.`code` = l.currency_code" //
@@ -649,6 +650,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
null, groupParentId, null, groupStaffId, null, groupHierarchy); null, groupParentId, null, groupStaffId, null, groupHierarchy);
} }
final Integer loanCounter = JdbcSupport.getInteger(rs, "loanCounter");
final Integer loanProductCounter = JdbcSupport.getInteger(rs, "loanProductCounter");
return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, groupData, return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, groupData,
loanType, loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanType, loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName,
loanOfficerId, loanOfficerName, currencyData, principal, totalOverpaid, inArrearsTolerance, termFrequency, loanOfficerId, loanOfficerName, currencyData, principal, totalOverpaid, inArrearsTolerance, termFrequency,
@@ -656,7 +660,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType,
interestCalculationPeriodType, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, interestCalculationPeriodType, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment,
graceOnInterestCharged, interestChargedFromDate, timeline, loanSummary, feeChargesDueAtDisbursementCharged, graceOnInterestCharged, interestChargedFromDate, timeline, loanSummary, feeChargesDueAtDisbursementCharged,
syncDisbursementWithMeeting); syncDisbursementWithMeeting, loanCounter, loanProductCounter);
} }
} }
@@ -39,7 +39,6 @@ import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeUpdatedExc
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException; import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException;
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException.LOAN_CHARGE_CANNOT_BE_WAIVED_REASON; import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException.LOAN_CHARGE_CANNOT_BE_WAIVED_REASON;
import org.mifosplatform.portfolio.charge.exception.LoanChargeNotFoundException; import org.mifosplatform.portfolio.charge.exception.LoanChargeNotFoundException;
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand; import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand; import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand;
import org.mifosplatform.portfolio.collectionsheet.command.SingleDisbursalCommand; import org.mifosplatform.portfolio.collectionsheet.command.SingleDisbursalCommand;
@@ -50,8 +49,6 @@ import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateM
import org.mifosplatform.portfolio.loanaccount.domain.Loan; import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge; import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
import org.mifosplatform.portfolio.loanaccount.domain.LoanChargeRepository; import org.mifosplatform.portfolio.loanaccount.domain.LoanChargeRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCycle;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCycleRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanLifecycleStateMachine; import org.mifosplatform.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory; import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository; import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
@@ -67,7 +64,6 @@ import org.mifosplatform.portfolio.loanaccount.exception.LoanTransactionNotFound
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory; import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
import org.mifosplatform.portfolio.loanaccount.serialization.LoanEventApiJsonValidator; import org.mifosplatform.portfolio.loanaccount.serialization.LoanEventApiJsonValidator;
import org.mifosplatform.portfolio.loanaccount.serialization.LoanUpdateCommandFromApiJsonDeserializer; import org.mifosplatform.portfolio.loanaccount.serialization.LoanUpdateCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail; import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.mifosplatform.portfolio.loanproduct.exception.InvalidCurrencyException; import org.mifosplatform.portfolio.loanproduct.exception.InvalidCurrencyException;
import org.mifosplatform.portfolio.note.domain.Note; import org.mifosplatform.portfolio.note.domain.Note;
@@ -98,7 +94,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final LoanScheduleGeneratorFactory loanScheduleFactory; private final LoanScheduleGeneratorFactory loanScheduleFactory;
private final CalendarInstanceRepository calendarInstanceRepository; private final CalendarInstanceRepository calendarInstanceRepository;
private final PaymentDetailWritePlatformService paymentDetailWritePlatformService; private final PaymentDetailWritePlatformService paymentDetailWritePlatformService;
private final LoanCycleRepository loanCycleRepository;
@Autowired @Autowired
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -110,7 +105,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final JournalEntryWritePlatformService journalEntryWritePlatformService, final LoanSummaryWrapper loanSummaryWrapper, final JournalEntryWritePlatformService journalEntryWritePlatformService, final LoanSummaryWrapper loanSummaryWrapper,
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory, final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
final LoanScheduleGeneratorFactory loanScheduleFactory, final CalendarInstanceRepository calendarInstanceRepository, final LoanScheduleGeneratorFactory loanScheduleFactory, final CalendarInstanceRepository calendarInstanceRepository,
final PaymentDetailWritePlatformService paymentDetailWritePlatformService, final LoanCycleRepository loanCycleRepository) { final PaymentDetailWritePlatformService paymentDetailWritePlatformService) {
this.context = context; this.context = context;
this.loanEventApiJsonValidator = loanEventApiJsonValidator; this.loanEventApiJsonValidator = loanEventApiJsonValidator;
this.loanAssembler = loanAssembler; this.loanAssembler = loanAssembler;
@@ -127,7 +122,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.loanScheduleFactory = loanScheduleFactory; this.loanScheduleFactory = loanScheduleFactory;
this.calendarInstanceRepository = calendarInstanceRepository; this.calendarInstanceRepository = calendarInstanceRepository;
this.paymentDetailWritePlatformService = paymentDetailWritePlatformService; this.paymentDetailWritePlatformService = paymentDetailWritePlatformService;
this.loanCycleRepository = loanCycleRepository;
} }
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() { private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
@@ -167,30 +161,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate"); final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
final LocalDate firstRepaymentMeetingDate = getFirstRepaymentMeetingDate(actualDisbursementDate, loan, calendarInstance); final LocalDate firstRepaymentMeetingDate = getFirstRepaymentMeetingDate(actualDisbursementDate, loan, calendarInstance);
// create loan cycle updateLoanCounters(loan, actualDisbursementDate);
final LoanProduct product = loan.loanProduct();
final Client client = loan.client();
// get the loan Ids which have disbursement date greater than
// 'actualDisbursementDate'.
final List<Long> loansToUpdateLoanCycle = this.loanRepository.getLoansDisbursedAfter(actualDisbursementDate.toDate());
// get all available loan cycles.
final List<LoanCycle> loanCycles = this.loanCycleRepository.findByClientIdAndLoanProductId(client.getId(), product.getId());
Integer loanCounter = loanCycles.size() + 1;
for (final long loanCycleLoanId : loansToUpdateLoanCycle) {
for (final LoanCycle loanCycle : loanCycles) {
if (loanCycle.loan().getId() == loanCycleLoanId) {
int runningCounter = loanCycle.getRunningCounter();
if (loanCounter > runningCounter) {
loanCounter = runningCounter;
}
loanCycle.updateLoanCycleCounter(++runningCounter);
}
}
}
final LoanCycle loanCycle = LoanCycle.create(client, product, loan, loanCounter);
this.loanCycleRepository.save(loanCycle);
loan.disburse(this.loanScheduleFactory, currentUser, command, applicationCurrency, existingTransactionIds, loan.disburse(this.loanScheduleFactory, currentUser, command, applicationCurrency, existingTransactionIds,
existingReversedTransactionIds, changes, paymentDetail, firstRepaymentMeetingDate); existingReversedTransactionIds, changes, paymentDetail, firstRepaymentMeetingDate);
@@ -1042,21 +1013,148 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
private void removeLoanCycle(final Loan loan) { private void removeLoanCycle(final Loan loan) {
final Client client = loan.client(); final List<Loan> loansToUpdate;
final LoanProduct product = loan.loanProduct(); if (loan.isGroupLoan()) {
final List<LoanCycle> loanCycles = this.loanCycleRepository.findByClientIdAndLoanProductId(client.getId(), product.getId()); if (loan.loanProduct().isIncludeInBorrowerCycle()) {
LoanCycle loanCycleToRemove = null; loansToUpdate = this.loanRepository.getGroupLoansToUpdateLoanCounter(loan.getCurrentLoanCounter(), loan.getGroupId(),
for (LoanCycle loanCycle : loanCycles) { LoanType.GROUP.getValue());
if (loanCycle.loan().getId().equals(loan.getId())) { } else {
loanCycleToRemove = loanCycle; loansToUpdate = this.loanRepository.getGroupLoansToUpdateLoanProductCounter(loan.getLoanProductLoanCounter(),
} else if (loanCycleToRemove != null) { loan.getGroupId(), LoanType.GROUP.getValue());
loanCycle = loanCycle.updateLoanCycleCounter(loanCycle.getRunningCounter() - 1); }
} else {
if (loan.loanProduct().isIncludeInBorrowerCycle()) {
loansToUpdate = this.loanRepository
.getClientOrJLGLoansToUpdateLoanCounter(loan.getCurrentLoanCounter(), loan.getClientId());
} else {
loansToUpdate = this.loanRepository.getClientLoansToUpdateLoanProductCounter(loan.getLoanProductLoanCounter(),
loan.getClientId());
}
}
if (loansToUpdate != null) {
updateLoanCycleCounter(loansToUpdate, loan);
}
loan.updateClientLoanCounter(null);
loan.updateLoanProductLoanCounter(null);
}
private void updateLoanCounters(final Loan loan, final LocalDate actualDisbursementDate) {
if (loan.isGroupLoan()) {
final List<Loan> loansToUpdateForLoanCounter = this.loanRepository.getGroupLoansDisbursedAfter(actualDisbursementDate.toDate(),
loan.getGroupId(), LoanType.GROUP.getValue());
final Integer newLoanCounter = getNewGroupLoanCounter(loan);
final Integer newLoanProductCounter = getNewGroupLoanProductCounter(loan);
updateLoanCounter(loan, loansToUpdateForLoanCounter, newLoanCounter, newLoanProductCounter);
} else {
final List<Loan> loansToUpdateForLoanCounter = this.loanRepository.getClientOrJLGLoansDisbursedAfter(
actualDisbursementDate.toDate(), loan.getClientId());
final Integer newLoanCounter = getNewClientOrJLGLoanCounter(loan);
final Integer newLoanProductCounter = getNewClientOrJLGLoanProductCounter(loan);
updateLoanCounter(loan, loansToUpdateForLoanCounter, newLoanCounter, newLoanProductCounter);
}
}
private Integer getNewGroupLoanCounter(final Loan loan) {
Integer maxClientLoanCounter = this.loanRepository.getMaxGroupLoanCounter(loan.getGroupId(), LoanType.GROUP.getValue());
if (maxClientLoanCounter == null) {
maxClientLoanCounter = 1;
} else {
maxClientLoanCounter = maxClientLoanCounter + 1;
}
return maxClientLoanCounter;
}
private Integer getNewGroupLoanProductCounter(final Loan loan) {
Integer maxLoanProductLoanCounter = this.loanRepository.getMaxGroupLoanProductCounter(loan.loanProduct().getId(),
loan.getGroupId(), LoanType.GROUP.getValue());
if (maxLoanProductLoanCounter == null) {
maxLoanProductLoanCounter = 1;
} else {
maxLoanProductLoanCounter = maxLoanProductLoanCounter + 1;
}
return maxLoanProductLoanCounter;
}
private void updateLoanCounter(final Loan loan, final List<Loan> loansToUpdateForLoanCounter, Integer newLoanCounter,
Integer newLoanProductCounter) {
final boolean includeInBorrowerCycle = loan.loanProduct().isIncludeInBorrowerCycle();
for (final Loan loanToUpdate : loansToUpdateForLoanCounter) {
//Update client loan counter if loan product includeInBorrowerCycle is true
if (includeInBorrowerCycle) {
Integer currentLoanCounter = loanToUpdate.getCurrentLoanCounter();
if (newLoanCounter > currentLoanCounter) {
newLoanCounter = currentLoanCounter;
}
loanToUpdate.updateClientLoanCounter(++currentLoanCounter);
}
if (loanToUpdate.loanProduct().getId().equals(loan.loanProduct().getId())) {
Integer loanProductLoanCounter = loanToUpdate.getLoanProductLoanCounter();
if (newLoanProductCounter > loanProductLoanCounter) {
newLoanProductCounter = loanProductLoanCounter;
}
loanToUpdate.updateLoanProductLoanCounter(++loanProductLoanCounter);
} }
} }
if (loanCycleToRemove != null) { if (includeInBorrowerCycle) {
this.loanCycleRepository.save(loanCycles); loan.updateClientLoanCounter(newLoanCounter);
this.loanCycleRepository.delete(loanCycleToRemove); } else {
loan.updateClientLoanCounter(null);
} }
loan.updateLoanProductLoanCounter(newLoanProductCounter);
this.loanRepository.save(loansToUpdateForLoanCounter);
}
private Integer getNewClientOrJLGLoanCounter(final Loan loan) {
Integer maxClientLoanCounter = this.loanRepository.getMaxClientOrJLGLoanCounter(loan.getClientId());
if (maxClientLoanCounter == null) {
maxClientLoanCounter = 1;
} else {
maxClientLoanCounter = maxClientLoanCounter + 1;
}
return maxClientLoanCounter;
}
private Integer getNewClientOrJLGLoanProductCounter(final Loan loan) {
Integer maxLoanProductLoanCounter = this.loanRepository.getMaxClientOrJLGLoanProductCounter(loan.loanProduct().getId(),
loan.getClientId());
if (maxLoanProductLoanCounter == null) {
maxLoanProductLoanCounter = 1;
} else {
maxLoanProductLoanCounter = maxLoanProductLoanCounter + 1;
}
return maxLoanProductLoanCounter;
}
private void updateLoanCycleCounter(final List<Loan> loansToUpdate, final Loan loan) {
final Integer currentLoancounter = loan.getCurrentLoanCounter();
final Integer currentLoanProductCounter = loan.getLoanProductLoanCounter();
for (final Loan loanToUpdate : loansToUpdate) {
if (loan.loanProduct().isIncludeInBorrowerCycle()) {
Integer runningLoancounter = loanToUpdate.getCurrentLoanCounter();
if (runningLoancounter > currentLoancounter) {
loanToUpdate.updateClientLoanCounter(--runningLoancounter);
}
}
if (loan.loanProduct().getId().equals(loanToUpdate.loanProduct().getId())) {
Integer runningLoanProductCounter = loanToUpdate.getLoanProductLoanCounter();
if (runningLoanProductCounter > currentLoanProductCounter) {
loanToUpdate.updateLoanProductLoanCounter(--runningLoanProductCounter);
}
}
}
this.loanRepository.save(loansToUpdate);
} }
} }
@@ -329,4 +329,8 @@ public class LoanProduct extends AbstractPersistable<Long> {
null, null, null, null) : this.loanProductMinMaxConstraints; null, null, null, null) : this.loanProductMinMaxConstraints;
return loanProductMinMaxConstraints; return loanProductMinMaxConstraints;
} }
public boolean isIncludeInBorrowerCycle() {
return this.includeInBorrowerCycle;
}
} }