org.mifos.framework.components.batchjobs.helpers.ApplyPenaltyToLoanAccountsHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.mifos.framework.components.batchjobs.helpers.ApplyPenaltyToLoanAccountsHelper.java

Source

/*
 * 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.framework.components.batchjobs.helpers;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import org.hibernate.Query;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.mifos.accounts.business.AccountPenaltiesEntity;
import org.mifos.accounts.loan.business.LoanBO;
import org.mifos.accounts.loan.business.LoanPenaltyScheduleEntity;
import org.mifos.accounts.loan.business.LoanScheduleEntity;
import org.mifos.accounts.penalties.business.AmountPenaltyBO;
import org.mifos.accounts.penalties.business.RatePenaltyBO;
import org.mifos.accounts.penalties.util.helpers.PenaltyPeriod;
import org.mifos.application.NamedQueryConstants;
import org.mifos.framework.components.batchjobs.SchedulerConstants;
import org.mifos.framework.components.batchjobs.TaskHelper;
import org.mifos.framework.components.batchjobs.exceptions.BatchJobException;
import org.mifos.framework.hibernate.helper.StaticHibernateUtil;
import org.mifos.framework.util.helpers.Money;

public class ApplyPenaltyToLoanAccountsHelper extends TaskHelper {
    private LocalDate currentLocalDate;
    private Date currentDate;

    @Override
    public void execute(final long timeInMillis) throws BatchJobException {
        setCurrentDates(timeInMillis);
        List<String> errorList = new ArrayList<String>();
        List<LoanBO> loanAccounts;

        try {
            loanAccounts = getLoanAccounts();
        } catch (Exception e) {
            throw new BatchJobException(e);
        }

        if (loanAccounts != null && !loanAccounts.isEmpty()) {
            Integer loanAccountId = null;

            try {
                for (LoanBO loanAccount : loanAccounts) {
                    loanAccountId = loanAccount.getAccountId();
                    List<AccountPenaltiesEntity> penaltyEntities = new ArrayList<AccountPenaltiesEntity>(
                            loanAccount.getAccountPenalties());

                    for (AccountPenaltiesEntity penaltyEntity : penaltyEntities) {
                        List<LoanScheduleEntity> lateInstallments = loanAccount.getDetailsOfLateInstallmentsPeriod(
                                new LocalDate(penaltyEntity.getCreatedDate()), currentLocalDate);

                        for (LoanScheduleEntity entity : lateInstallments) {

                            //check grace period for installment period type
                            if (penaltyEntity.getPenalty().getPeriodType()
                                    .getPenaltyPeriod() == PenaltyPeriod.INSTALLMENTS
                                    && penaltyEntity.hasPeriodType()) {
                                if (lateInstallments.get(0).getInstallmentId().equals(entity.getInstallmentId())
                                        && checkGracePeriodTypeInstallments(lateInstallments,
                                                penaltyEntity.getPenalty().getPeriodDuration())) {
                                    continue;
                                }
                            }
                            //check grace period for daily period type
                            else if (penaltyEntity.getPenalty().getPeriodType()
                                    .getPenaltyPeriod() == PenaltyPeriod.DAYS && penaltyEntity.hasPeriodType()) {
                                if (checkGracePeriodTypeDays(entity,
                                        penaltyEntity.getPenalty().getPeriodDuration())) {
                                    continue;
                                }
                            }

                            LoanPenaltyScheduleEntity penaltySchedule = entity
                                    .getPenaltyScheduleEntity(penaltyEntity.getPenalty().getPenaltyId());

                            if (checkPeriod(penaltyEntity, new LocalDate(entity.getActionDate().getTime()))
                                    || (penaltySchedule != null && penaltySchedule.isOn(currentLocalDate))) {
                                continue;
                            }

                            if (penaltyEntity.isAmountPenalty()) {
                                addAmountPenalty(penaltyEntity, loanAccount, entity);
                            } else {
                                addRatePenalty(penaltyEntity, loanAccount, entity);
                            }
                        }
                    }
                }
            } catch (Exception e) {
                if (loanAccountId != null) {
                    getLogger().error(String.format(
                            "ApplyPenaltyToLoanAccountsTask execute failed with exception %s: %s at loan account %s",
                            e.getClass().getName(), e.getMessage(), loanAccountId.toString()), e);

                    errorList.add(loanAccountId.toString());
                }

                StaticHibernateUtil.rollbackTransaction();
            } finally {
                StaticHibernateUtil.closeSession();
            }
        }

        if (!errorList.isEmpty()) {
            throw new BatchJobException(SchedulerConstants.FAILURE, errorList);
        }
    }

    private boolean checkPeriod(AccountPenaltiesEntity penaltyEntity, LocalDate installmentDate) {
        int days = Days.daysBetween(installmentDate, currentLocalDate).getDays();
        boolean check = false;
        boolean oneTime = penaltyEntity.isOneTime();

        if (oneTime && penaltyEntity.getLastAppliedDate() != null) {
            check = true;
        } else if (!oneTime && ((penaltyEntity.isMonthlyTime() && days % 31 != 1)
                || penaltyEntity.isWeeklyTime() && days % 7 != 1)) {
            check = true;
        }

        return check;
    }

    private boolean checkGracePeriodTypeInstallments(final List<LoanScheduleEntity> lateInstallments,
            final int duration) {
        boolean check = false;

        if (lateInstallments.size() - 1 < duration) {
            check = true;
        } else if (lateInstallments.size() - 1 == duration) {
            check = lateInstallments.get(duration).isOn(currentLocalDate.minusDays(1));
        } else {
            check = false;
        }
        return check;
    }

    private boolean checkGracePeriodTypeDays(final LoanScheduleEntity entity, final int duration) {
        boolean check = false;

        int days = Days.daysBetween(new LocalDate(entity.getActionDate().getTime()), currentLocalDate).getDays();
        check = days <= duration;

        return check;
    }

    private void addAmountPenalty(final AccountPenaltiesEntity penaltyEntity, final LoanBO loanAccount,
            final LoanScheduleEntity loanScheduleEntity) {
        AmountPenaltyBO penalty = (AmountPenaltyBO) penaltyEntity.getPenalty();
        Money accountPenaltyAmount = penaltyEntity.getAccountPenaltyAmount();
        Money charge = verifyLimits(
                loanAccount.getTotalPenalty(accountPenaltyAmount.getCurrency(), penalty.getPenaltyId()),
                accountPenaltyAmount,
                penalty.getMinimumLimit() / loanAccount.calcFactorOfEntireLoan().doubleValue(),
                penalty.getMaximumLimit() / loanAccount.calcFactorOfEntireLoan().doubleValue());

        if (charge != null && charge.isGreaterThanZero()) {
            loanAccount.applyPenalty(charge, loanScheduleEntity.getInstallmentId(), penaltyEntity, currentDate);
        }

        try {
            StaticHibernateUtil.startTransaction();
            StaticHibernateUtil.getSessionTL().update(loanAccount);
            StaticHibernateUtil.commitTransaction();
        } catch (Exception e) {
            getLogger().error(e.getMessage());
            StaticHibernateUtil.rollbackTransaction();
        }
    }

    private void addRatePenalty(final AccountPenaltiesEntity penaltyEntity, final LoanBO loanAccount,
            final LoanScheduleEntity loanScheduleEntity) {
        RatePenaltyBO penalty = (RatePenaltyBO) penaltyEntity.getPenalty();
        Double radio = penaltyEntity.getAccountPenaltyAmount().getAmount().doubleValue() / 100.0d;
        Money charge = null;

        if (penalty.isOutstandingPrincipalAmount()) {
            charge = loanAccount.getLoanSummary().getOriginalPrincipal().multiply(radio);
        } else if (penalty.isOutstandingLoanAmount()) {
            charge = loanAccount.getLoanSummary().getOutstandingBalance().multiply(radio);
        } else if (penalty.isOverdueAmountDue()) {
            charge = loanScheduleEntity.getTotalDue().multiply(radio);
        } else if (penalty.isOverduePrincipal()) {
            charge = loanScheduleEntity.getPrincipalDue().multiply(radio);
        } else {
            charge = Money.zero();
        }

        Money totalPenalty = loanAccount.getTotalPenalty(charge.getCurrency(), penalty.getPenaltyId());
        charge = verifyLimits(totalPenalty, charge,
                penalty.getMinimumLimit() / loanAccount.calcFactorOfEntireLoan().doubleValue(),
                penalty.getMaximumLimit() / loanAccount.calcFactorOfEntireLoan().doubleValue());

        if (charge.isGreaterThanZero()) {
            loanAccount.applyPenalty(charge, loanScheduleEntity.getInstallmentId(), penaltyEntity, currentDate);
        }

        try {
            StaticHibernateUtil.startTransaction();
            StaticHibernateUtil.getSessionTL().update(loanAccount);
            StaticHibernateUtil.commitTransaction();
        } catch (Exception e) {
            getLogger().error(e.getMessage());
            StaticHibernateUtil.rollbackTransaction();
        }
    }

    private Money verifyLimits(final Money total, final Money charge, final Double min, final double max) {
        Money cash = charge;
        boolean zero = total.isZero();

        if (zero && charge.getAmount().doubleValue() < min) {
            cash = new Money(charge.getCurrency(), min);
        } else if (!zero && total.add(charge).getAmount().doubleValue() > max) {
            cash = new Money(charge.getCurrency(), max - total.getAmount().doubleValue());
        }

        return cash;
    }

    private List<LoanBO> getLoanAccounts() {
        Query select = StaticHibernateUtil.getSessionTL()
                .getNamedQuery(NamedQueryConstants.GET_ALL_LOAN_ACCOUNTS_WITH_PENALTIES);
        select.setDate("currentDate", currentDate);

        return castList(LoanBO.class, select.list());
    }

    private <T> List<T> castList(final Class<? extends T> clazz, final Collection<?> collection) {
        List<T> results = new ArrayList<T>(collection.size());

        for (Object item : collection) {
            results.add(clazz.cast(item));
        }

        return results;
    }

    private void setCurrentDates(long time) {
        currentLocalDate = new LocalDate(time);
        currentDate = new Date(time);
    }

}