use of org.mifos.accounts.exceptions.AccountException in project head by mifos.
the class LoanBO method waiveFeeAmountDue.
private void waiveFeeAmountDue() throws AccountException {
List<AccountActionDateEntity> accountActionDateList = getApplicableIdsForNextInstallmentAndArrears();
LoanScheduleEntity accountActionDateEntity = (LoanScheduleEntity) accountActionDateList.get(accountActionDateList.size() - 1);
Money chargeWaived = accountActionDateEntity.waiveFeeCharges();
Money principal = new Money(getCurrency());
Money interest = new Money(getCurrency());
Money penalty = new Money(getCurrency());
if (chargeWaived != null && chargeWaived.isGreaterThanZero()) {
updateTotalFeeAmount(chargeWaived);
updateAccountActivity(principal, interest, chargeWaived, penalty, userContext.getId(), LoanConstants.FEE_WAIVED);
waiveChargesFromMemberAccounts(LoanConstants.FEE_WAIVED);
}
try {
getlegacyLoanDao().createOrUpdate(this);
} catch (PersistenceException e) {
throw new AccountException(e);
}
}
use of org.mifos.accounts.exceptions.AccountException in project head by mifos.
the class LoanBO method getLastUnpaidInstallment.
private AccountActionDateEntity getLastUnpaidInstallment() throws AccountException {
Set<AccountActionDateEntity> accountActionDateSet = getAccountActionDates();
List<AccountActionDateEntity> objectList = Arrays.asList(accountActionDateSet.toArray(new AccountActionDateEntity[accountActionDateSet.size()]));
for (int i = objectList.size() - 1; i >= 0; i--) {
AccountActionDateEntity accountActionDateEntity = objectList.get(i);
if (accountActionDateEntity.isNotPaid()) {
return accountActionDateEntity;
}
}
throw new AccountException(AccountConstants.NOMOREINSTALLMENTS);
}
use of org.mifos.accounts.exceptions.AccountException in project head by mifos.
the class LoanBO method changeLoanStatus.
private void changeLoanStatus(final AccountState newAccountState, final PersonnelBO personnel) throws AccountException {
AccountStateEntity accountState = this.getAccountState();
try {
setAccountState(legacyMasterDao.getPersistentObject(AccountStateEntity.class, newAccountState.getValue()));
} catch (PersistenceException e) {
throw new AccountException(e);
}
if (newAccountState.isClosedLoanAccountState() || newAccountState.isCancelledLoanAccountState()) {
changeStateForAllFees(FeeStatus.INACTIVE);
} else if (newAccountState.isActiveLoanAccountState()) {
changeStateForAllFees(FeeStatus.ACTIVE);
}
this.addAccountStatusChangeHistory(new AccountStatusChangeHistoryEntity(accountState, this.getAccountState(), personnel, this));
}
use of org.mifos.accounts.exceptions.AccountException in project head by mifos.
the class LoanBO method updateInstallmentAfterAdjustment.
@Override
protected void updateInstallmentAfterAdjustment(final List<AccountTrxnEntity> reversedTrxns, PersonnelBO loggedInUser) throws AccountException {
Money increaseInterest = new Money(this.getCurrency());
Money increaseFees = new Money(this.getCurrency());
Money increasePenalty = new Money(this.getCurrency());
int numberOfFullPayments = 0;
short numberOfInstalments = (short) reversedTrxns.size();
List<AccountActionDateEntity> allInstallments = this.getAllInstallments();
if (isNotEmpty(reversedTrxns)) {
for (AccountTrxnEntity reversedTrxn : reversedTrxns) {
Short prevInstallmentId = null;
Short currentInstallmentId = reversedTrxn.getInstallmentId();
numberOfFullPayments = getIncrementedNumberOfFullPaymentsIfPaid(numberOfFullPayments, allInstallments, prevInstallmentId, currentInstallmentId);
if (!reversedTrxn.isTrxnForReversalOfLoanDisbursal()) {
LoanTrxnDetailEntity loanReverseTrxn = (LoanTrxnDetailEntity) reversedTrxn;
loanSummary.updatePaymentDetails(loanReverseTrxn);
if (loanReverseTrxn.isNotEmptyTransaction()) {
LoanScheduleEntity installment = (LoanScheduleEntity) getAccountActionDate(loanReverseTrxn.getInstallmentId());
installment.updatePaymentDetailsForAdjustment(loanReverseTrxn);
if (installment.isPaid()) {
increaseInterest = increaseInterest.add(installment.getInterestDue().add(installment.getExtraInterestDue())).add(loanReverseTrxn.getInterestAmount());
increaseFees = increaseFees.add(installment.getTotalFeesDue());
if (!this.noOfInstallments.equals(numberOfInstalments)) {
increaseFees = increaseFees.add(installment.getMiscFeeDue()).add(loanReverseTrxn.getMiscFeeAmount());
increasePenalty = increasePenalty.add(installment.getPenaltyDue()).add(loanReverseTrxn.getPenaltyAmount());
}
}
installment.recordForAdjustment();
if (installment.hasFees()) {
for (AccountFeesActionDetailEntity accntFeesAction : installment.getAccountFeesActionDetails()) {
loanReverseTrxn.adjustFees(accntFeesAction);
}
}
if (installment.hasPenalties()) {
for (LoanPenaltyScheduleEntity entity : installment.getLoanPenaltyScheduleEntities()) {
loanReverseTrxn.adjustPenalties(entity);
}
}
}
}
}
AccountStateEntity currentAccountState = this.getAccountState();
AccountStateEntity newAccountState = currentAccountState;
boolean statusChangeNeeded = false;
if (isLoanActiveWithStatusChangeHistory()) {
AccountStatusChangeHistoryEntity lastAccountStatusChange = getLastAccountStatusChange();
if (lastAccountStatusChange.isLoanActive()) {
statusChangeNeeded = true;
} else if (currentAccountState.isLoanClosedObligationsMet()) {
statusChangeNeeded = true;
newAccountState = lastAccountStatusChange.getOldStatus();
}
}
boolean accountReOpened = isAccountReOpened(currentAccountState, newAccountState);
updatePerformanceHistory(accountReOpened);
/*
* John W - mifos-1986 - see related comment above
*/
if (accountReOpened) {
loanSummary.increaseBy(null, increaseInterest, increasePenalty, increaseFees);
// fix for MIFOS-3287
this.setClosedDate(null);
}
// Else reverse payments equal to number of transactions reversed.
if (accountReOpened) {
updatePerformanceHistoryOnAdjustment(1);
} else if (reversedTrxns.size() > 0) {
updatePerformanceHistoryOnAdjustment(numberOfFullPayments);
}
if (statusChangeNeeded) {
Short daysInArrears = getDaysInArrears(accountReOpened);
if (currentAccountState.isLoanClosedObligationsMet()) {
AccountState newStatus = AccountState.LOAN_ACTIVE_IN_BAD_STANDING;
if (daysInArrears == 0) {
newStatus = AccountState.LOAN_ACTIVE_IN_GOOD_STANDING;
}
changeStatus(newStatus, null, "Account Reopened", loggedInUser);
} else {
if (daysInArrears == 0) {
if (!currentAccountState.isLoanActiveInGoodStanding()) {
changeStatus(AccountState.LOAN_ACTIVE_IN_GOOD_STANDING, null, "Account Adjusted", loggedInUser);
}
} else {
if (!currentAccountState.isLoanActiveInBadStanding()) {
changeStatus(AccountState.LOAN_ACTIVE_IN_BAD_STANDING, null, "Account Adjusted", loggedInUser);
handleArrearsAging();
}
}
}
}
try {
PersonnelBO personnel = legacyPersonnelDao.getPersonnel(getUserContext().getId());
addLoanActivity(buildLoanActivity(reversedTrxns, personnel, AccountConstants.LOAN_ADJUSTED, DateUtils.getCurrentDateWithoutTimeStamp()));
} catch (PersistenceException e) {
throw new AccountException(e);
}
}
}
use of org.mifos.accounts.exceptions.AccountException in project head by mifos.
the class LoanBO method regeneratePaymentSchedule.
/**
* pull this logic out of LoanBO entity and reuse LoanSchedule behaviour used from service facades at a service level
*/
@Deprecated
private void regeneratePaymentSchedule(final boolean isRepaymentIndepOfMeetingEnabled, final MeetingBO newMeetingForRepaymentDay) throws AccountException {
Money miscFee = getMiscFee();
Money miscPenalty = getMiscPenalty();
try {
getlegacyLoanDao().deleteInstallments(this.getAccountActionDates());
} catch (PersistenceException e) {
throw new AccountException(e);
}
// Delete previous loan meeting if loan is parent account and set individual loans(if any) loanMeeting same as parent
if (isRepaymentIndepOfMeetingEnabled && newMeetingForRepaymentDay != null && !this.getLoanMeeting().equals(newMeetingForRepaymentDay)) {
if (null != this.getLoanMeeting() && !this.isIndividualLoan()) {
this.delete(this.getLoanMeeting());
}
setLoanMeeting(newMeetingForRepaymentDay);
if (this.hasMemberAccounts()) {
for (LoanBO individualLoanBO : this.getMemberAccounts()) {
individualLoanBO.setLoanMeeting(newMeetingForRepaymentDay);
}
}
}
this.resetAccountActionDates();
loanMeeting.setMeetingStartDate(disbursementDate);
RecurringScheduledEventFactory scheduledEventFactory = new RecurringScheduledEventFactoryImpl();
ScheduledEvent meetingScheduledEvent = scheduledEventFactory.createScheduledEventFrom(this.loanMeeting);
LoanInstallmentFactory loanInstallmentFactory = new LoanInstallmentFactoryImpl(scheduledEventFactory);
LoanInstallmentGenerator loanInstallmentGenerator = loanInstallmentFactory.create(this.getLoanMeeting(), isRepaymentIndepOfMeetingEnabled);
LocalDate actualDisbursementDate = new LocalDate(this.disbursementDate);
List<InstallmentDate> installmentDates = loanInstallmentGenerator.generate(actualDisbursementDate, this.noOfInstallments, this.gracePeriodType.asEnum(), this.gracePeriodDuration, this.office.getOfficeId());
Integer numberOfInstallments = installmentDates.size();
GraceType graceType = this.gracePeriodType.asEnum();
InterestType interestType = InterestType.fromInt(this.interestType.getId());
Integer interestDays = AccountingRules.getNumberOfInterestDays().intValue();
LoanDecliningInterestAnnualPeriodCalculator decliningInterestAnnualPeriodCalculator = new LoanDecliningInterestAnnualPeriodCalculatorFactory().create(loanMeeting.getRecurrenceType());
Double decliningInterestAnnualPeriod = decliningInterestAnnualPeriodCalculator.calculate(loanMeeting.getRecurAfter().intValue(), interestDays);
Double interestFractionalRatePerInstallment = interestRate / decliningInterestAnnualPeriod / 100;
LoanDurationInAccountingYearsCalculator loanDurationInAccountingYearsCalculator = new LoanDurationInAccountingYearsCalculatorFactory().create(loanMeeting.getRecurrenceType());
Double durationInYears = loanDurationInAccountingYearsCalculator.calculate(loanMeeting.getRecurAfter().intValue(), numberOfInstallments, interestDays);
List<DateTime> scheduledInstallments = new ArrayList<DateTime>();
for (InstallmentDate installmentDate : installmentDates) {
scheduledInstallments.add(new DateTime(installmentDate.getInstallmentDueDate()));
}
LoanInterestCalculationDetails loanInterestCalculationDetails = new LoanInterestCalculationDetails(loanAmount, interestRate, graceType, gracePeriodDuration.intValue(), numberOfInstallments, durationInYears, interestFractionalRatePerInstallment, actualDisbursementDate, scheduledInstallments);
LoanInterestCalculatorFactory loanInterestCalculatorFactory = new LoanInterestCalculatorFactoryImpl();
LoanInterestCalculator loanInterestCalculator = loanInterestCalculatorFactory.create(interestType, this.loanOffering.isVariableInstallmentsAllowed());
Money loanInterest = loanInterestCalculator.calculate(loanInterestCalculationDetails);
EqualInstallmentGeneratorFactory equalInstallmentGeneratorFactory = new EqualInstallmentGeneratorFactoryImpl();
PrincipalWithInterestGenerator equalInstallmentGenerator = equalInstallmentGeneratorFactory.create(interestType, loanInterest, this.loanOffering.isVariableInstallmentsAllowed());
List<InstallmentPrincipalAndInterest> principalWithInterestInstallments = equalInstallmentGenerator.generateEqualInstallments(loanInterestCalculationDetails);
List<LoanScheduleEntity> unroundedLoanSchedules = createUnroundedLoanSchedulesFromInstallments(installmentDates, loanInterest, this.loanAmount, meetingScheduledEvent, principalWithInterestInstallments, this.getAccountFees());
Money rawAmount = calculateTotalFeesAndInterestForLoanSchedules(unroundedLoanSchedules);
if (loanSummary == null) {
// save it to LoanBO first and when loan summary is created it will
// be retrieved and save to loan summary
setRawAmountTotal(rawAmount);
} else {
loanSummary.setRawAmountTotal(rawAmount);
}
List<LoanScheduleEntity> allExistingLoanSchedules = new ArrayList<LoanScheduleEntity>();
LoanScheduleRounderHelper loanScheduleRounderHelper = new DefaultLoanScheduleRounderHelper();
LoanScheduleRounder loanScheduleInstallmentRounder = getLoanScheduleRounder(loanScheduleRounderHelper);
List<LoanScheduleEntity> roundedLoanSchedules = loanScheduleInstallmentRounder.round(graceType, gracePeriodDuration, loanAmount, interestType, unroundedLoanSchedules, allExistingLoanSchedules);
for (LoanScheduleEntity roundedLoanSchedule : roundedLoanSchedules) {
addAccountActionDate(roundedLoanSchedule);
}
LoanScheduleEntity loanScheduleEntity = (LoanScheduleEntity) getAccountActionDate((short) 1);
loanScheduleEntity.setMiscFee(miscFee);
loanScheduleEntity.setMiscPenalty(miscPenalty);
Money interest = new Money(getCurrency());
Money fees = new Money(getCurrency());
Money penalty = new Money(getCurrency());
Money principal = new Money(getCurrency());
Set<AccountActionDateEntity> actionDates = getAccountActionDates();
if (actionDates != null && actionDates.size() > 0) {
for (AccountActionDateEntity accountActionDate : actionDates) {
LoanScheduleEntity loanSchedule = (LoanScheduleEntity) accountActionDate;
principal = principal.add(loanSchedule.getPrincipal());
interest = interest.add(loanSchedule.getInterest());
fees = fees.add(loanSchedule.getTotalFeesDueWithMiscFee());
penalty = penalty.add(loanSchedule.getTotalPenalty());
}
}
fees = fees.add(getDisbursementFeeAmount());
loanSummary.setOriginalInterest(interest);
loanSummary.setOriginalFees(fees);
loanSummary.setOriginalPenalty(penalty);
}
Aggregations