added status for charges

This commit is contained in:
Pramod Nuthakki
2014-01-16 09:59:41 +05:30
committed by Vishwas Babu A J
parent 45785dff42
commit 8b5eab1d87
6 changed files with 93 additions and 45 deletions
@@ -0,0 +1,2 @@
ALTER TABLE `m_loan_charge`
ADD COLUMN `is_active` TINYINT(1) NOT NULL DEFAULT '1' AFTER `max_cap`;
@@ -217,7 +217,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
sql.append("and (gp.status_enum = 300 or (gp.status_enum = 600 and gp.closedon_date >= :dueDate)) ")
.append("and (cl.status_enum = 300 or (cl.status_enum = 600 and cl.closedon_date >= :dueDate)) ")
.append("GROUP BY gp.id ,cl.id , ln.id ORDER BY gp.id , cl.id , ln.id ").append(") loandata ")
.append("LEFT JOIN m_loan_charge lc ON lc.loan_id = loandata.loanId AND lc.is_paid_derived = 0 ")
.append("LEFT JOIN m_loan_charge lc ON lc.loan_id = loandata.loanId AND lc.is_paid_derived = 0 AND lc.is_active = 1")
.append("AND ( lc.due_for_collection_as_of_date <= :dueDate OR lc.charge_time_enum = 1) ")
.append("GROUP BY loandata.groupId, ").append("loandata.clientId, ").append("loandata.loanId ")
.append("ORDER BY loandata.groupId, ").append("loandata.clientId, ").append("loandata.loanId ");
@@ -83,6 +83,7 @@ import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleM
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductBorrowerCycleVariations;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
@@ -374,7 +375,7 @@ public class Loan extends AbstractPersistable<Long> {
Money chargesDue = Money.of(getCurrency(), BigDecimal.ZERO);
for (final LoanCharge charge : setOfLoanCharges()) {
for (final LoanCharge charge : charges()) {
if (charge.isDueAtDisbursement()) {
chargesDue = chargesDue.plus(charge.amount());
}
@@ -453,7 +454,7 @@ public class Loan extends AbstractPersistable<Long> {
// NOTE: must add new loan charge to set of loan charges before
// reporcessing the repayment schedule.
setOfLoanCharges().add(loanCharge);
charges().add(loanCharge);
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategy);
@@ -463,11 +464,11 @@ public class Loan extends AbstractPersistable<Long> {
existingTransactionIds.addAll(findExistingTransactionIds());
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, setOfLoanCharges());
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, charges());
if (!loanCharge.isDueAtDisbursement()) {
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, charges());
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
mapEntry.getValue().updateLoan(this);
}
@@ -591,10 +592,12 @@ public class Loan extends AbstractPersistable<Long> {
// if you want ability to remove loan charges that are waived.
validateLoanChargeIsNotWaived(loanCharge);
final boolean removed = setOfLoanCharges().remove(loanCharge);
LoanCharge charge = fetchLoanChargesById(loanCharge.getId());
final boolean removed = charge.isActive();
if (removed) {
charge.setActive(false);
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, setOfLoanCharges());
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, charges());
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
}
@@ -613,7 +616,7 @@ public class Loan extends AbstractPersistable<Long> {
***/
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement,
getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
getCurrency(), this.repaymentScheduleInstallments, charges());
}
updateLoanSummaryDerivedFields();
@@ -651,7 +654,7 @@ public class Loan extends AbstractPersistable<Long> {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(3);
validateLoanIsNotClosed(loanCharge);
if (setOfLoanCharges().contains(loanCharge)) {
if (charges().contains(loanCharge)) {
final BigDecimal amount = calculateAmountPercentageAppliedTo(loanCharge);
final Map<String, Object> loanChargeChanges = loanCharge.update(command, amount);
actualChanges.putAll(loanChargeChanges);
@@ -671,11 +674,11 @@ public class Loan extends AbstractPersistable<Long> {
***/
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement,
getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
getCurrency(), this.repaymentScheduleInstallments, charges());
} else {
// reprocess loan schedule based on charge been waived.
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, setOfLoanCharges());
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, charges());
}
updateLoanSummaryDerivedFields();
@@ -798,11 +801,11 @@ public class Loan extends AbstractPersistable<Long> {
***/
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement,
getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
getCurrency(), this.repaymentScheduleInstallments, charges());
} else {
// reprocess loan schedule based on charge been waived.
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, setOfLoanCharges());
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, charges());
}
updateLoanSummaryDerivedFields();
@@ -861,9 +864,16 @@ public class Loan extends AbstractPersistable<Long> {
}
public void updateLoanCharges(final Set<LoanCharge> loanCharges) {
setOfLoanCharges().clear();
List<Long> existingCharges = fetchAllLoanChargeIds();
for (final LoanCharge loanCharge : loanCharges) {
loanCharge.update(this);
LoanCharge charge = loanCharge;
if(loanCharge.getId() == null){
loanCharge.update(this);
this.charges.add(loanCharge);
}else{
charge = fetchLoanChargesById(charge.getId());
existingCharges.remove(charge.getId());
}
final BigDecimal amount = calculateAmountPercentageAppliedTo(loanCharge);
BigDecimal chargeAmt = BigDecimal.ZERO;
BigDecimal totalChargeAmt = BigDecimal.ZERO;
@@ -878,10 +888,12 @@ public class Loan extends AbstractPersistable<Long> {
chargeAmt = chargeAmt.divide(BigDecimal.valueOf(repaymentScheduleDetail().getNumberOfRepayments()));
}
}
loanCharge.update(chargeAmt, loanCharge.getDueLocalDate(), amount, repaymentScheduleDetail().getNumberOfRepayments(),
charge.update(chargeAmt, loanCharge.getDueLocalDate(), amount, repaymentScheduleDetail().getNumberOfRepayments(),
totalChargeAmt);
}
setOfLoanCharges().addAll(loanCharges);
for(Long id:existingCharges){
fetchLoanChargesById(id).setActive(false);
}
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
}
@@ -915,7 +927,7 @@ public class Loan extends AbstractPersistable<Long> {
}
private void clearInstallmentLoanCharge() {
for (final LoanCharge loanCharge : setOfLoanCharges()) {
for (final LoanCharge loanCharge : charges()) {
if (loanCharge.isInstalmentFee()) {
loanCharge.clearLoanInstallmentCharges();
}
@@ -1129,7 +1141,7 @@ public class Loan extends AbstractPersistable<Long> {
final String chargesParamName = "charges";
if (command.parameterExists(chargesParamName)) {
final Set<LoanCharge> existingLoanCharges = setOfLoanCharges();
final Set<LoanCharge> existingLoanCharges = charges();
if (!possiblyModifedLoanCharges.equals(existingLoanCharges)) {
actualChanges.put(chargesParamName, getLoanCharges(possiblyModifedLoanCharges));
@@ -1185,14 +1197,6 @@ public class Loan extends AbstractPersistable<Long> {
return actualChanges;
}
private Set<LoanCharge> setOfLoanCharges() {
Set<LoanCharge> loanCharges = this.charges;
if (this.charges == null) {
loanCharges = new HashSet<LoanCharge>();
}
return loanCharges;
}
private CollateralData[] listOfLoanCollateralData(final Set<LoanCollateral> setOfLoanCollateral) {
CollateralData[] existingLoanCollateral = null;
@@ -1284,7 +1288,7 @@ public class Loan extends AbstractPersistable<Long> {
}
// charges are optional
for (final LoanCharge loanCharge : setOfLoanCharges()) {
for (final LoanCharge loanCharge : charges()) {
final BigDecimal amount = calculateAmountPercentageAppliedTo(loanCharge);
BigDecimal chargeAmt = BigDecimal.ZERO;
BigDecimal totalChargeAmt = BigDecimal.ZERO;
@@ -1588,7 +1592,7 @@ public class Loan extends AbstractPersistable<Long> {
loanTermPeriodFrequencyType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(),
calculatedRepaymentsStartingFromDate, getInArrearsTolerance(), this.loanRepaymentScheduleDetail);
final LoanScheduleModel loanSchedule = loanScheduleGenerator.generate(mc, applicationCurrency, loanApplicationTerms, this.charges,
final LoanScheduleModel loanSchedule = loanScheduleGenerator.generate(mc, applicationCurrency, loanApplicationTerms,charges(),
isHolidayEnabled, holidays, workingDays);
updateLoanSchedule(loanSchedule);
@@ -1618,7 +1622,7 @@ public class Loan extends AbstractPersistable<Long> {
Money disbursentMoney = Money.zero(getCurrency());
final LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(getOffice(), disbursentMoney, null, disbursedOn,
null);
for (final LoanCharge charge : setOfLoanCharges()) {
for (final LoanCharge charge : charges()) {
if (charge.isDueAtDisbursement()) {
if (totalFeeChargesDueAtDisbursement.isGreaterThanZero() && !charge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
charge.markAsFullyPaid();
@@ -1662,7 +1666,7 @@ public class Loan extends AbstractPersistable<Long> {
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
LoanCharge charge = null;
for (final LoanCharge loanCharge : this.charges) {
if (chargeId.equals(loanCharge.getId())) {
if (loanCharge.isActive() && chargeId.equals(loanCharge.getId())) {
charge = loanCharge;
}
}
@@ -1728,7 +1732,7 @@ public class Loan extends AbstractPersistable<Long> {
private void updateLoanToPreDisbursalState() {
this.actualDisbursementDate = null;
for (final LoanCharge charge : setOfLoanCharges()) {
for (final LoanCharge charge : charges()) {
charge.resetToOriginal(loanCurrency());
}
@@ -1737,7 +1741,7 @@ public class Loan extends AbstractPersistable<Long> {
}
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, setOfLoanCharges());
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, charges());
updateLoanSummaryDerivedFields();
}
@@ -1799,7 +1803,7 @@ public class Loan extends AbstractPersistable<Long> {
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
LoanCharge charge = null;
for (final LoanCharge loanCharge : this.charges) {
if (chargeId.equals(loanCharge.getId())) {
if (loanCharge.isActive() && chargeId.equals(loanCharge.getId())) {
charge = loanCharge;
}
}
@@ -1890,11 +1894,11 @@ public class Loan extends AbstractPersistable<Long> {
.determineProcessor(this.transactionProcessingStrategy);
if (isTransactionChronologicallyLatest && adjustedTransaction == null) {
loanRepaymentScheduleTransactionProcessor.handleTransaction(loanTransaction, getCurrency(), this.repaymentScheduleInstallments,
setOfLoanCharges());
charges());
} else {
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, charges());
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
mapEntry.getValue().updateLoan(this);
}
@@ -1939,7 +1943,8 @@ public class Loan extends AbstractPersistable<Long> {
boolean isAllChargesPaid = true;
for (final LoanCharge loanCharge : this.charges) {
if (!(loanCharge.isPaid() || loanCharge.isWaived())) {
if (loanCharge.isActive()
&& !(loanCharge.isPaid() || loanCharge.isWaived())) {
isAllChargesPaid = false;
break;
}
@@ -2138,7 +2143,7 @@ public class Loan extends AbstractPersistable<Long> {
.determineProcessor(this.transactionProcessingStrategy);
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, charges());
updateLoanSummaryDerivedFields();
return changedTransactionDetail;
}
@@ -3046,7 +3051,15 @@ public class Loan extends AbstractPersistable<Long> {
}
public Set<LoanCharge> charges() {
return this.charges;
Set<LoanCharge> loanCharges = new HashSet<LoanCharge>();
if(this.charges != null){
for(LoanCharge charge:this.charges){
if(charge.isActive()){
loanCharges.add(charge);
}
}
}
return loanCharges;
}
public Set<LoanInstallmentCharge> generateInstallmentLoanCharges(final LoanCharge loanCharge) {
@@ -3115,7 +3128,7 @@ public class Loan extends AbstractPersistable<Long> {
}
break;
case LOAN_REJECTED:
if (!isClosedWrittenOff()) {
if (!isSubmittedAndPendingApproval()) {
final String defaultUserMessage = "Loan application cannot be rejected. Loan Account is not in Submitted and Pending approval state.";
final ApiParameterError error = ApiParameterError.generalError(
"error.msg.loan.reject.account.is.not.submitted.pending.approval.state", defaultUserMessage);
@@ -3149,7 +3162,7 @@ public class Loan extends AbstractPersistable<Long> {
case REPAID_IN_FULL:
break;
case LOAN_CHARGE_PAYMENT:
if (!isClosedWrittenOff()) {
if (!isOpen()) {
final String defaultUserMessage = "Charge payment is not allowed. Loan Account is not Active.";
final ApiParameterError error = ApiParameterError.generalError("error.msg.loan.charge.payment.account.is.not.active",
defaultUserMessage);
@@ -3157,7 +3170,7 @@ public class Loan extends AbstractPersistable<Long> {
}
break;
case LOAN_CLOSED:
if (!isClosedWrittenOff()) {
if (!isOpen()) {
final String defaultUserMessage = "Closing Loan Account is not allowed. Loan Account is not Active.";
final ApiParameterError error = ApiParameterError.generalError("error.msg.loan.close.account.is.not.active",
defaultUserMessage);
@@ -3171,4 +3184,24 @@ public class Loan extends AbstractPersistable<Long> {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
public LoanCharge fetchLoanChargesById(Long id) {
LoanCharge charge = null;
for (LoanCharge loanCharge : this.charges) {
if (id.equals(loanCharge.getId())) {
charge = loanCharge;
break;
}
}
return charge;
}
private List<Long> fetchAllLoanChargeIds() {
List<Long> list = new ArrayList<Long>();
for (LoanCharge loanCharge : this.charges) {
list.add(loanCharge.getId());
}
return list;
}
}
@@ -108,6 +108,10 @@ public class LoanCharge extends AbstractPersistable<Long> {
@LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loancharge", orphanRemoval = true)
private final Set<LoanInstallmentCharge> loanInstallmentCharge = new HashSet<LoanInstallmentCharge>();
@Column(name = "is_active", nullable = false)
private boolean active = true;
public static LoanCharge createNewFromJson(final Loan loan, final Charge chargeDefinition, final JsonCommand command) {
@@ -769,4 +773,13 @@ public class LoanCharge extends AbstractPersistable<Long> {
}
return null;
}
public boolean isActive(){
return this.active;
}
public void setActive(boolean active) {
this.active = active;
}
}
@@ -151,7 +151,7 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
final LoanChargeMapper rm = new LoanChargeMapper();
final String sql = "select " + rm.schema() + " where lc.loan_id=? "
final String sql = "select " + rm.schema() + " where lc.loan_id=? AND lc.is_active = 1"
+ " order by lc.charge_time_enum ASC, lc.due_for_collection_as_of_date ASC, lc.is_penalty ASC";
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
@@ -161,7 +161,7 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
public Collection<LoanChargeData> retrieveLoanChargesForFeePayment(final Integer paymentMode, final Integer loanStatus) {
final LoanChargeMapperWithLoanId rm = new LoanChargeMapperWithLoanId();
final String sql = "select " + rm.schema()
+ "where loan.loan_status_id= ? and lc.charge_payment_mode_enum=? and lc.waived =0 and lc.is_paid_derived=0";
+ "where loan.loan_status_id= ? and lc.charge_payment_mode_enum=? and lc.waived =0 and lc.is_paid_derived=0 and lc.is_active = 1";
return this.jdbcTemplate.query(sql, rm, new Object[] { loanStatus, paymentMode });
}
@@ -1156,7 +1156,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
+ " where DATE_SUB(CURDATE(),INTERVAL ? DAY) > ls.duedate "
+ " and ls.completed_derived <> 1 and mc.charge_applies_to_enum =1 "
+ " and mc.charge_time_enum = 9 and ml.loan_status_id = 300 "
+ " and plc.charge_id not in (SELECT charge_id from m_loan_charge as mlc where mlc.loan_id = ml.id and mlc.charge_id = plc.charge_id and mlc.due_for_collection_as_of_date > fromdate AND mlc.due_for_collection_as_of_date <= duedate) ";
+ " and plc.charge_id not in (SELECT charge_id from m_loan_charge as mlc where mlc.loan_id = ml.id and mlc.charge_id = plc.charge_id and mlc.is_active = 1 and mlc.due_for_collection_as_of_date > fromdate AND mlc.due_for_collection_as_of_date <= duedate) ";
return this.jdbcTemplate.query(sql, rm, new Object[] { penaltyWaitPeriod });
}