/*
* Copyright (c) 2005-2011 Grameen Foundation USA
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* See also http://www.apache.org/licenses/LICENSE-2.0.html for an
* explanation of the license and how it is applied.
*/
package org.mifos.customers.client.business;
import static org.apache.commons.lang.math.NumberUtils.SHORT_ZERO;
import static org.mifos.customers.client.business.LoanCounter.TRANSFORM_LOAN_COUNTER_TO_LOAN_CYCLE;
import static org.mifos.framework.util.CollectionUtils.find;
import static org.mifos.framework.util.CollectionUtils.select;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.mifos.accounts.business.AccountBO;
import org.mifos.accounts.loan.business.LoanBO;
import org.mifos.accounts.productdefinition.business.LoanOfferingBO;
import org.mifos.accounts.productdefinition.business.PrdOfferingBO;
import org.mifos.application.master.business.MifosCurrency;
import org.mifos.application.util.helpers.YesNoFlag;
import org.mifos.customers.business.CustomerPerformanceHistory;
import org.mifos.framework.util.helpers.Money;
import org.mifos.framework.util.helpers.Predicate;
public class ClientPerformanceHistoryEntity extends CustomerPerformanceHistory {
private final Integer id;
private Set<LoanCounter> loanCounters;
private Integer noOfActiveLoans;
private Money lastLoanAmount;
private Money delinquentPortfolio;
private Money totalSavings;
private ClientBO client;
public void setClient(ClientBO client) {
this.client = client;
}
public ClientPerformanceHistoryEntity(ClientBO client) {
super();
this.id = null;
this.client = client;
this.loanCounters = new HashSet<LoanCounter>();
this.noOfActiveLoans = 0;
this.lastLoanAmount = new Money(getCurrency());
this.delinquentPortfolio = new Money(getCurrency());
this.totalSavings = new Money(getCurrency());
}
protected ClientPerformanceHistoryEntity() {
this.id = null;
this.client = null;
this.loanCounters = new HashSet<LoanCounter>();
this.noOfActiveLoans = 0;
this.lastLoanAmount = null;
this.delinquentPortfolio = null;
this.totalSavings = null;
}
public Integer getId() {
return id;
}
@SuppressWarnings("unused")
private Money getDelinquentPortfolio() {
return delinquentPortfolio;
}
@SuppressWarnings("unused")
private void setDelinquentPortfolio(Money delinquentPortfolio) {
this.delinquentPortfolio = delinquentPortfolio;
}
public Money getLastLoanAmount() {
return lastLoanAmount;
}
public void setLastLoanAmount(Money lastLoanAmount) {
this.lastLoanAmount = lastLoanAmount;
}
public Set<LoanCounter> getLoanCounters() {
return loanCounters;
}
public void setLoanCounters(Set<LoanCounter> loanCounters) {
this.loanCounters = loanCounters;
}
private void addLoanCounter(LoanCounter loanCounter) {
this.loanCounters.add(loanCounter);
}
public Integer getNoOfActiveLoans() {
return noOfActiveLoans;
}
public void setNoOfActiveLoans(Integer noOfActiveLoans) {
this.noOfActiveLoans = noOfActiveLoans;
}
@SuppressWarnings("unused")
private Money getTotalSavings() {
return totalSavings;
}
public Money getTotalSavingsAmount() {
return getClient().getSavingsBalance(getCurrency());
}
@SuppressWarnings("unused")
private void setTotalSavings(Money totalSavings) {
this.totalSavings = totalSavings;
}
public ClientBO getClient() {
return client;
}
public void updateLoanCounter(final LoanOfferingBO loanOffering, YesNoFlag counterFlag) {
if (loanCounters == null) {
loanCounters = new HashSet<LoanCounter>();
}
LoanCounter loanCounter = null;
try {
loanCounter = findLoanCounterForProduct(loanOffering);
} catch (Exception e) {
}
if (loanCounter == null) {
loanCounter = new LoanCounter(this, loanOffering, counterFlag);
addLoanCounter(loanCounter);
} else {
loanCounter.updateLoanCounter(counterFlag);
}
}
public LoanCounter findLoanCounterForProduct(final LoanOfferingBO loanOffering) throws Exception {
return find(loanCounters, new Predicate<LoanCounter>() {
@Override
public boolean evaluate(LoanCounter loanCounter) {
return loanOffering.isOfSameOffering(loanCounter.getLoanOffering());
}
});
}
public MifosCurrency getCurrency() {
// TODO: performance history will only work if all accounts use the default (or same?) currency
return Money.getDefaultCurrency();
}
public Integer getLoanCycleNumber() {
Integer loanCount = 0;
for (LoanCounter loanCounter : getLoanCounters()) {
if (loanCounter.getLoanOffering().isIncludeInLoanCounter()) {
loanCount += loanCounter.getLoanCycleCounter();
}
}
if (client.getHistoricalData() != null) {
if (client.getHistoricalData().getLoanCycleNumber() == null) {
client.getHistoricalData().setLoanCycleNumber(0);
}
loanCount += client.getHistoricalData().getLoanCycleNumber();
}
return loanCount;
}
public Money getDelinquentPortfolioAmount() {
// we don't know what currency to use when we start totaling these
// so don't initialize them with a currency
Money amountOverDue = null;
Money totalOutStandingAmount = null;
for (AccountBO accountBO : client.getAccounts()) {
if (accountBO.isLoanAccount() && ((LoanBO) accountBO).isAccountActive()) {
Money totalPrincipalAmountInArrears = ((LoanBO) accountBO).getTotalPrincipalAmountInArrears();
if (amountOverDue == null) {
amountOverDue = totalPrincipalAmountInArrears;
} else {
amountOverDue = amountOverDue.add(totalPrincipalAmountInArrears);
}
Money originalPrincipal = ((LoanBO) accountBO).getLoanSummary().getOriginalPrincipal();
if (totalOutStandingAmount == null) {
totalOutStandingAmount = originalPrincipal;
} else {
totalOutStandingAmount = totalOutStandingAmount.add(originalPrincipal);
}
}
}
// FIXME: this seems like it should just be returning a BigDecimal rather than a Money object
if (totalOutStandingAmount != null && !totalOutStandingAmount.getAmount().equals(BigDecimal.ZERO)) {
return new Money(amountOverDue.getCurrency(), amountOverDue.divide(totalOutStandingAmount));
}
return new Money(getCurrency());
}
public Short getMaxLoanCycleForProduct(final PrdOfferingBO prdOffering) {
{
Set<LoanCounter> clientLoanCounters = getLoanCounters();
try {
Collection<Short> loanCyclesForProduct = select(clientLoanCounters, new Predicate<LoanCounter>() {
@Override
public boolean evaluate(LoanCounter counter) {
return counter.isOfSameProduct(prdOffering);
}
}, TRANSFORM_LOAN_COUNTER_TO_LOAN_CYCLE);
return loanCyclesForProduct.isEmpty() ? SHORT_ZERO : Collections.max(loanCyclesForProduct);
} catch (Exception e) {
return SHORT_ZERO;
}
}
}
public void updateOnDisbursement(LoanOfferingBO loanOffering) {
updateLoanCounter(loanOffering, YesNoFlag.YES);
incrementNoOfActiveLoans();
}
public void updateOnWriteOff(LoanOfferingBO loanOffering) {
updateLoanCounter(loanOffering, YesNoFlag.NO);
decrementNoOfActiveLoans();
}
public void updateOnReversal(LoanOfferingBO loanOffering, Money lastLoanAmount) {
updateCommonHistoryOnReversal(loanOffering);
}
public void updateCommonHistoryOnReversal(LoanOfferingBO loanOffering) {
updateLoanCounter(loanOffering, YesNoFlag.NO);
decrementNoOfActiveLoans();
}
public void updateOnFullRepayment(Money totalAmount) {
setLastLoanAmount(totalAmount);
decrementNoOfActiveLoans();
}
public void incrementNoOfActiveLoans(){
setNoOfActiveLoans(getNoOfActiveLoans() + 1);
}
public void decrementNoOfActiveLoans(){
setNoOfActiveLoans(getNoOfActiveLoans() - 1);
}
}