/*
* 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.accounts.penalties.business;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.mifos.accounts.financial.business.GLCodeEntity;
import org.mifos.accounts.penalties.exceptions.PenaltyException;
import org.mifos.accounts.penalties.util.helpers.PenaltyConstants;
import org.mifos.accounts.penalties.util.helpers.PenaltyFrequency;
import org.mifos.accounts.penalties.util.helpers.PenaltyStatus;
import org.mifos.accounts.persistence.LegacyAccountDao;
import org.mifos.application.servicefacade.ApplicationContextProvider;
import org.mifos.config.AccountingRules;
import org.mifos.dto.domain.PenaltyDto;
import org.mifos.framework.business.AbstractBusinessObject;
import org.mifos.framework.exceptions.PersistenceException;
import org.mifos.framework.util.helpers.Money;
import org.mifos.security.util.UserContext;
public abstract class PenaltyBO extends AbstractBusinessObject {
private final Short penaltyId;
private String penaltyName;
private PenaltyStatusEntity status;
private final PenaltyCategoryEntity categoryType;
private PenaltyPeriodEntity periodType;
private Integer periodDuration;
private Double minimumLimit;
private Double maximumLimit;
private PenaltyFrequencyEntity penaltyFrequency;
private GLCodeEntity glCode;
protected PenaltyBO(final UserContext userContext, final String name, final PenaltyCategoryEntity categoryEntity,
final PenaltyPeriodEntity periodEntity, final Integer duration, final Double min, final Double max,
final PenaltyFrequencyEntity frequencyEntity, final GLCodeEntity glCodeEntity) throws PenaltyException {
validateFields(name, categoryEntity, periodEntity, min, max, frequencyEntity, glCodeEntity);
setUserContext(userContext);
setCreateDetails();
this.penaltyId = null;
this.penaltyName = name;
this.status = new PenaltyStatusEntity(PenaltyStatus.ACTIVE);
this.categoryType = categoryEntity;
this.periodType = periodEntity;
this.periodDuration = duration;
this.minimumLimit = min;
this.maximumLimit = max;
this.penaltyFrequency = frequencyEntity;
this.glCode = glCodeEntity;
}
protected PenaltyBO() {
this.penaltyId = null;
this.penaltyName = null;
this.status = null;
this.categoryType = null;
this.periodType = null;
this.periodDuration = null;
this.minimumLimit = null;
this.maximumLimit = null;
this.penaltyFrequency = null;
this.glCode = null;
}
public String getPenaltyName() {
return penaltyName;
}
public void setPenaltyName(String penaltyName) {
this.penaltyName = penaltyName;
}
public PenaltyStatusEntity getStatus() {
return status;
}
public void setStatus(PenaltyStatusEntity status) {
this.status = status;
}
public PenaltyPeriodEntity getPeriodType() {
return periodType;
}
public void setPeriodType(PenaltyPeriodEntity periodType) {
this.periodType = periodType;
}
public Integer getPeriodDuration() {
return periodDuration;
}
public void setPeriodDuration(Integer periodDuration) {
this.periodDuration = periodDuration;
}
public Double getMinimumLimit() {
return minimumLimit;
}
public void setMinimumLimit(Double minimumLimit) {
this.minimumLimit = minimumLimit;
}
public Double getMaximumLimit() {
return maximumLimit;
}
public void setMaximumLimit(Double maximumLimit) {
this.maximumLimit = maximumLimit;
}
public PenaltyFrequencyEntity getPenaltyFrequency() {
return penaltyFrequency;
}
public void setPenaltyFrequency(PenaltyFrequencyEntity penaltyFrequency) {
this.penaltyFrequency = penaltyFrequency;
}
public GLCodeEntity getGlCode() {
return glCode;
}
public void setGlCode(GLCodeEntity glCode) {
this.glCode = glCode;
}
public Short getPenaltyId() {
return penaltyId;
}
public PenaltyCategoryEntity getCategoryType() {
return categoryType;
}
public boolean isOneTime() {
return getPenaltyFrequency().isOneTime();
}
public boolean isDailyTime() {
return getPenaltyFrequency().isDailyTime();
}
public boolean isWeeklyTime() {
return getPenaltyFrequency().isWeeklyTime();
}
public boolean isMonthlyTime() {
return getPenaltyFrequency().isMonthlyTime();
}
public PenaltyDto toDto() {
PenaltyDto dto = new PenaltyDto();
dto.setPenaltyId(Short.toString(this.penaltyId));
dto.setPenaltyName(this.penaltyName);
dto.setStatus(this.status.toDto());
dto.setCategoryType(this.categoryType.toDto());
dto.setPeriodType(this.periodType.toDto());
dto.setPeriodDuration(this.periodDuration == null ? null : Integer.toString(this.periodDuration));
dto.setMinimumLimit(Double.toString(this.minimumLimit));
dto.setMaximumLimit(Double.toString(this.maximumLimit));
dto.setPenaltyFrequency(this.penaltyFrequency.toDto());
dto.setGlCodeDto(this.glCode.toDto());
if (this instanceof AmountPenaltyBO) {
Money amount = ((AmountPenaltyBO) this).getAmount();
dto.setCurrencyId(amount.getCurrency().getCurrencyId().intValue());
dto.setAmount(amount.toString(AccountingRules.getDigitsAfterDecimal()));
dto.setRateBasedPenalty(false);
} else {
RatePenaltyBO rate = (RatePenaltyBO) this;
dto.setRate(rate.getRate());
dto.setPenaltyFormula(rate.getFormula().toDto());
dto.setRateBasedPenalty(true);
}
return dto;
}
public void save() throws PenaltyException {
try {
ApplicationContextProvider.getBean(LegacyAccountDao.class).createOrUpdate(this);
} catch (PersistenceException he) {
throw new PenaltyException(PenaltyConstants.PENALTY_CREATE_ERROR, he);
}
}
@Override
public boolean equals(Object obj) {
PenaltyBO rhs = (PenaltyBO) obj;
return new EqualsBuilder().append(this.penaltyId, rhs.penaltyId).append(this.penaltyName, rhs.penaltyName).isEquals();
}
@Override
public int hashCode() {
int initialNonZeroOddNumber = 7;
int multiplierNonZeroOddNumber = 7;
return new HashCodeBuilder(initialNonZeroOddNumber, multiplierNonZeroOddNumber).append(this.penaltyId).append(this.penaltyName).hashCode();
}
@Override
public String toString() {
return new StringBuilder().append(this.penaltyId).append(" : ").append(this.penaltyName).toString();
}
/**
* Returns true if any penalties applied to an installment might be an amount
* that exceeds the precision specified by initial or final rounding of
* amounts in an installment. This check is required temporarily in order to
* prevent re-rounding when a penalty is added after payments have been made.
*/
public abstract boolean doesPenaltyInvolveFractionalAmounts();
protected void validateFields(String name, PenaltyCategoryEntity categoryEntity, PenaltyPeriodEntity periodEntity,
Double min, Double max, PenaltyFrequencyEntity frequencyEntity, GLCodeEntity glCodeEntity) throws PenaltyException {
validateName(name);
validateCategory(categoryEntity);
validatePeriod(periodEntity);
validateMinAndMax(min, max);
validateFrequency(frequencyEntity);
validateGLCode(glCodeEntity);
}
private void validateName(final String name) throws PenaltyException {
if (StringUtils.isBlank(name)) {
throw new PenaltyException(PenaltyConstants.INVALID_PENALTY_NAME);
}
}
private void validateCategory(final PenaltyCategoryEntity category) throws PenaltyException {
if (category == null) {
throw new PenaltyException(PenaltyConstants.INVALID_PENALTY_CATEGORY);
}
}
private void validatePeriod(final PenaltyPeriodEntity periodEntity) throws PenaltyException {
if (periodEntity == null) {
throw new PenaltyException(PenaltyConstants.INVALID_PENALTY_PERIOD);
}
}
private void validateMinAndMax(final Double min, final Double max) throws PenaltyException {
if (min == null) {
throw new PenaltyException(PenaltyConstants.INVALID_PENALTY_MINIMUM);
}
if (max == null) {
throw new PenaltyException(PenaltyConstants.INVALID_PENALTY_MAXIMUM);
}
if (min.compareTo(max) > 0) {
throw new PenaltyException(PenaltyConstants.INVALID_MAX_GREATER_MIN);
}
}
private void validateFrequency(final PenaltyFrequencyEntity frequencyEntity) throws PenaltyException {
if (frequencyEntity == null) {
throw new PenaltyException(PenaltyConstants.INVALID_PENALTY_FREQUENCY);
}
}
private void validateGLCode(final GLCodeEntity glCode) throws PenaltyException {
if (glCode == null) {
throw new PenaltyException(PenaltyConstants.INVALID_GLCODE);
}
}
}