/*
* 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.fees.business;
import java.util.Date;
import java.util.Set;
import junit.framework.Assert;
import org.junit.After;
import org.junit.Test;
import org.mifos.accounts.fees.exceptions.FeeException;
import org.mifos.accounts.fees.util.helpers.FeeCategory;
import org.mifos.accounts.fees.util.helpers.FeeChangeType;
import org.mifos.accounts.fees.util.helpers.FeeConstants;
import org.mifos.accounts.fees.util.helpers.FeeFormula;
import org.mifos.accounts.fees.util.helpers.FeeFrequencyType;
import org.mifos.accounts.fees.util.helpers.FeeLevel;
import org.mifos.accounts.fees.util.helpers.FeePayment;
import org.mifos.accounts.fees.util.helpers.FeeStatus;
import org.mifos.accounts.financial.business.GLCodeEntity;
import org.mifos.application.meeting.business.MeetingBO;
import org.mifos.application.meeting.exceptions.MeetingException;
import org.mifos.application.meeting.util.helpers.MeetingType;
import org.mifos.application.meeting.util.helpers.RecurrenceType;
import org.mifos.framework.MifosIntegrationTestCase;
import org.mifos.framework.TestUtils;
import org.mifos.framework.exceptions.PropertyNotFoundException;
import org.mifos.framework.hibernate.helper.StaticHibernateUtil;
import org.mifos.framework.util.helpers.TestObjectFactory;
public class FeeBOIntegrationTest extends MifosIntegrationTestCase {
private FeeBO fee;
@After
public void tearDown() throws Exception {
fee = null;
StaticHibernateUtil.flushSession();
}
@Test
public void testCreateWithoutFeeName() throws Exception {
try {
fee = new AmountFeeBO(TestUtils.makeUser(), "", new CategoryTypeEntity(FeeCategory.CENTER),
new FeeFrequencyTypeEntity(FeeFrequencyType.ONETIME), getGLCode("7"),
TestUtils.createMoney("100"), false, new FeePaymentEntity(FeePayment.UPFRONT));
Assert.assertFalse("Fee is created without fee name", true);
} catch (FeeException e) {
Assert.assertNull(fee);
Assert.assertEquals(e.getKey(), FeeConstants.INVALID_FEE_NAME);
}
}
@Test
public void testCreateWithoutFeeCategory() throws Exception {
try {
fee = new AmountFeeBO(TestUtils.makeUser(), "Customer Fee", null, new FeeFrequencyTypeEntity(
FeeFrequencyType.ONETIME), getGLCode("7"), TestUtils.createMoney("100"), false,
new FeePaymentEntity(FeePayment.UPFRONT));
Assert.assertFalse("Fee is created without fee category", true);
} catch (FeeException e) {
Assert.assertNull(fee);
Assert.assertEquals(e.getKey(), FeeConstants.INVALID_FEE_CATEGORY);
}
}
@Test
public void testCreateFeeWithoutFeeFrequency() throws Exception {
try {
fee = new AmountFeeBO(TestUtils.makeUser(), "Customer Fee", new CategoryTypeEntity(FeeCategory.CENTER),
null, getGLCode("7"), TestUtils.createMoney("100"), false, new FeePaymentEntity(
FeePayment.UPFRONT));
Assert.assertFalse("Fee is created without frequency type", true);
} catch (FeeException e) {
Assert.assertNull(fee);
Assert.assertEquals(e.getKey(), FeeConstants.INVALID_FEE_FREQUENCY_TYPE);
}
}
@Test
public void testCreateAmountFeeWithoutAmount() throws Exception {
try {
fee = new AmountFeeBO(TestUtils.makeUser(), "Customer Fee", new CategoryTypeEntity(FeeCategory.CENTER),
new FeeFrequencyTypeEntity(FeeFrequencyType.ONETIME), getGLCode("7"), null, false,
new FeePaymentEntity(FeePayment.UPFRONT));
Assert.assertFalse("Fee is created without Amount", true);
} catch (FeeException e) {
Assert.assertNull(fee);
Assert.assertEquals(e.getKey(), FeeConstants.INVALID_FEE_AMOUNT);
}
}
@Test
public void testCreateRateFeeWithoutRate() throws Exception {
try {
FeeFormulaEntity feeFormula = new FeeFormulaEntity(FeeFormula.AMOUNT);
fee = new RateFeeBO(TestUtils.makeUser(), "Customer Fee", new CategoryTypeEntity(FeeCategory.CENTER),
new FeeFrequencyTypeEntity(FeeFrequencyType.ONETIME), getGLCode("7"), null, feeFormula, false,
new FeePaymentEntity(FeePayment.UPFRONT));
Assert.assertFalse("Fee is created without Rate", true);
} catch (FeeException e) {
Assert.assertNull(fee);
Assert.assertEquals(e.getKey(), FeeConstants.INVALID_FEE_RATE_OR_FORMULA);
}
}
@Test
public void testCreateRateFeeWithoutFormula() throws Exception {
try {
fee = new RateFeeBO(TestUtils.makeUser(), "Customer Fee", new CategoryTypeEntity(FeeCategory.CENTER),
new FeeFrequencyTypeEntity(FeeFrequencyType.ONETIME), getGLCode("7"), 2.0, null, false,
new FeePaymentEntity(FeePayment.UPFRONT));
Assert.assertFalse("Fee is created without Formula", true);
} catch (FeeException e) {
Assert.assertNull(fee);
Assert.assertEquals(e.getKey(), FeeConstants.INVALID_FEE_RATE_OR_FORMULA);
}
}
@Test
public void testCreateOneTimeAmountFee() throws Exception {
String name = "Customer_OneTime_AmountFee";
fee = createOneTimeAmountFee(name, FeeCategory.CENTER, "100", false, FeePayment.UPFRONT);
fee.save();
StaticHibernateUtil.flushSession();
fee = (FeeBO) TestObjectFactory.getObject(FeeBO.class, fee.getFeeId());
Assert.assertEquals(name, fee.getFeeName());
Assert.assertEquals(FeeCategory.CENTER.getValue(), fee.getCategoryType().getId());
StaticHibernateUtil.flushSession();
}
@Test
public void testDoesFeeInvolveFractionalAmountsForWholeAmountFee() throws Exception {
String name = "Customer_OneTime_AmountFee";
fee = createOneTimeAmountFee(name, FeeCategory.CENTER, "100", false, FeePayment.UPFRONT);
fee.save();
StaticHibernateUtil.flushSession();
fee = (FeeBO) TestObjectFactory.getObject(FeeBO.class, fee.getFeeId());
Assert.assertFalse(fee.doesFeeInvolveFractionalAmounts());
}
@Test
public void testDoesFeeInvolveFractionalAmountsForFractionalAmountFee() throws Exception {
String name = "Customer_OneTime_AmountFee";
fee = createOneTimeAmountFee(name, FeeCategory.CENTER, "100.23", false, FeePayment.UPFRONT);
fee.save();
StaticHibernateUtil.flushSession();
fee = (FeeBO) TestObjectFactory.getObject(FeeBO.class, fee.getFeeId());
Assert.assertTrue(fee.doesFeeInvolveFractionalAmounts());
}
@Test
public void testDoesFeeInvolveFractionalAmountsForRateFee() throws Exception {
fee = createOneTimeRateFee("Customer_OneTime_RateFee", FeeCategory.CENTER, 100.0, FeeFormula.AMOUNT, false,
FeePayment.UPFRONT);
fee.save();
StaticHibernateUtil.flushSession();
fee = (FeeBO) TestObjectFactory.getObject(FeeBO.class, fee.getFeeId());
Assert.assertTrue(fee.doesFeeInvolveFractionalAmounts());
}
@Test
public void testCreateOneTimeRateFee() throws Exception {
fee = createOneTimeRateFee("Customer_OneTime_RateFee", FeeCategory.CENTER, 100.0, FeeFormula.AMOUNT, false,
FeePayment.UPFRONT);
fee.save();
StaticHibernateUtil.flushSession();
fee = (FeeBO) TestObjectFactory.getObject(FeeBO.class, fee.getFeeId());
Assert.assertEquals("Customer_OneTime_RateFee", fee.getFeeName());
Assert.assertEquals(FeeCategory.CENTER.getValue(), fee.getCategoryType().getId());
}
@Test
public void testCreatePeriodicAmountFee() throws Exception {
MeetingBO feefrequency = new MeetingBO(RecurrenceType.WEEKLY, Short.valueOf("2"), new Date(),
MeetingType.PERIODIC_FEE);
fee = createPeriodicAmountFee("Customer_Periodic_AmountFee", FeeCategory.CENTER, "100", false, feefrequency);
fee.save();
StaticHibernateUtil.flushSession();
fee = (FeeBO) TestObjectFactory.getObject(FeeBO.class, fee.getFeeId());
Assert.assertEquals("Customer_Periodic_AmountFee", fee.getFeeName());
Assert.assertEquals(FeeCategory.CENTER.getValue(), fee.getCategoryType().getId());
StaticHibernateUtil.flushSession();
}
@Test
public void testCreatePeriodicRateFee() throws Exception {
MeetingBO feefrequency = new MeetingBO(RecurrenceType.WEEKLY, Short.valueOf("2"), new Date(),
MeetingType.PERIODIC_FEE);
fee = createPeriodicRateFee("Customer_Periodic_RateFee", FeeCategory.CENTER, 100.0, FeeFormula.AMOUNT, false,
feefrequency);
fee.save();
StaticHibernateUtil.flushSession();
fee = (FeeBO) TestObjectFactory.getObject(FeeBO.class, fee.getFeeId());
Assert.assertEquals("Customer_Periodic_RateFee", fee.getFeeName());
Assert.assertEquals(FeeCategory.CENTER.getValue(), fee.getCategoryType().getId());
}
@Test
public void testCreateOneTimeDefaultFee() throws Exception {
fee = createOneTimeAmountFee("Customer_OneTime_DefaultFee", FeeCategory.GROUP, "100", true, FeePayment.UPFRONT);
fee.save();
StaticHibernateUtil.flushSession();
fee = (FeeBO) TestObjectFactory.getObject(FeeBO.class, fee.getFeeId());
Assert.assertEquals("Customer_OneTime_DefaultFee", fee.getFeeName());
Assert.assertEquals(FeeCategory.GROUP.getValue(), fee.getCategoryType().getId());
Assert.assertTrue(fee.isCustomerDefaultFee());
Assert.assertTrue(vaidateDefaultCustomerFee(fee.getFeeLevels(), fee.getCategoryType().getFeeCategory()));
StaticHibernateUtil.flushSession();
}
@Test
public void testCreatePeriodicDefaultFee() throws Exception {
MeetingBO feefrequency = new MeetingBO(RecurrenceType.WEEKLY, Short.valueOf("2"), new Date(),
MeetingType.PERIODIC_FEE);
fee = createPeriodicRateFee("Customer_Periodic_DefaultFee", FeeCategory.ALLCUSTOMERS, 100.0, FeeFormula.AMOUNT,
true, feefrequency);
fee.save();
StaticHibernateUtil.flushSession();
fee = (FeeBO) TestObjectFactory.getObject(FeeBO.class, fee.getFeeId());
Assert.assertEquals("Customer_Periodic_DefaultFee", fee.getFeeName());
Assert.assertEquals(FeeCategory.ALLCUSTOMERS.getValue(), fee.getCategoryType().getId());
Assert.assertEquals(true, fee.isCustomerDefaultFee());
Assert.assertTrue(vaidateDefaultCustomerFee(fee.getFeeLevels(), fee.getCategoryType().getFeeCategory()));
StaticHibernateUtil.flushSession();
}
@Test
public void testFeeLevel() {
Assert.assertEquals(FeeLevel.CENTERLEVEL, FeeLevel.getFeeLevel(FeeLevel.CENTERLEVEL.getValue()));
Assert.assertEquals(null, FeeLevel.getFeeLevel(Short.valueOf("99")));
}
private boolean vaidateDefaultCustomerFee(Set<FeeLevelEntity> defaultCustomers, FeeCategory feeCategory) {
boolean bCenter = false;
boolean bGroup = false;
boolean bClient = false;
for (FeeLevelEntity feeLevel : defaultCustomers) {
if (feeLevel.getLevelId().equals(FeeLevel.CENTERLEVEL.getValue())) {
bCenter = true;
}
if (feeLevel.getLevelId().equals(FeeLevel.GROUPLEVEL.getValue())) {
bGroup = true;
}
if (feeLevel.getLevelId().equals(FeeLevel.CLIENTLEVEL.getValue())) {
bClient = true;
}
}
if (feeCategory.equals(FeeCategory.CENTER)) {
return bCenter && !bGroup && !bClient;
}
if (feeCategory.equals(FeeCategory.GROUP)) {
return !bCenter && bGroup && !bClient;
}
if (feeCategory.equals(FeeCategory.CLIENT)) {
return !bCenter && !bGroup && bClient;
}
if (feeCategory.equals(FeeCategory.ALLCUSTOMERS)) {
return bCenter && bGroup && bClient;
}
return !bCenter && !bGroup && !bClient;
}
private FeeBO createOneTimeRateFee(String feeName, FeeCategory feeCategory, Double rate, FeeFormula feeFormula,
boolean isDefaultFee, FeePayment feePayment) throws Exception {
return new RateFeeBO(TestUtils.makeUser(), feeName, new CategoryTypeEntity(feeCategory),
new FeeFrequencyTypeEntity(FeeFrequencyType.ONETIME), getGLCode("7"), rate, new FeeFormulaEntity(
feeFormula), isDefaultFee, new FeePaymentEntity(feePayment));
}
private FeeBO createPeriodicRateFee(String feeName, FeeCategory feeCategory, Double rate, FeeFormula feeFormula,
boolean isDefaultFee, MeetingBO feeFrequency) throws Exception {
return new RateFeeBO(TestUtils.makeUser(), feeName, new CategoryTypeEntity(feeCategory),
new FeeFrequencyTypeEntity(FeeFrequencyType.PERIODIC), getGLCode("7"), rate, new FeeFormulaEntity(
feeFormula), isDefaultFee, feeFrequency);
}
private FeeBO createOneTimeAmountFee(String feeName, FeeCategory feeCategory, String amount, boolean isDefaultFee,
FeePayment feePayment) throws Exception {
return new AmountFeeBO(TestUtils.makeUser(), feeName, new CategoryTypeEntity(feeCategory),
new FeeFrequencyTypeEntity(FeeFrequencyType.ONETIME), getGLCode("7"),
TestUtils.createMoney(amount), isDefaultFee, new FeePaymentEntity(feePayment));
}
private FeeBO createPeriodicAmountFee(String feeName, FeeCategory feeCategory, String amount, boolean isDefaultFee,
MeetingBO feeFrequency) throws Exception {
return new AmountFeeBO(TestUtils.makeUser(), feeName, new CategoryTypeEntity(feeCategory),
new FeeFrequencyTypeEntity(FeeFrequencyType.PERIODIC), getGLCode("7"),
TestUtils.createMoney(amount), isDefaultFee, feeFrequency);
}
private GLCodeEntity getGLCode(String id) {
return (GLCodeEntity) TestObjectFactory.getObject(GLCodeEntity.class, Short.valueOf(id));
}
@Test
public void testAmountFeeBOUpdateChangeTypeSetsNotUpdated() throws Exception {
AmountFeeBO feeToChange = createAmountFeeToTestChangeFeeType();
AmountFeeBO newFee = createAmountFeeToTestChangeFeeType();
feeToChange.calculateNewFeeChangeType(newFee.getFeeAmount(), newFee.getFeeStatus());
assertFeeChangeType(FeeChangeType.NOT_UPDATED, feeToChange);
}
@Test
public void testAmountFeeBOUpdateChangeTypeSetsAmountUpdated() throws Exception {
AmountFeeBO feeToChange = createAmountFeeToTestChangeFeeType();
AmountFeeBO newFee = (AmountFeeBO) createPeriodicAmountFee("fee", FeeCategory.ALLCUSTOMERS, "2000", true,
createMeeting());
feeToChange.updateFeeChangeType(feeToChange.calculateNewFeeChangeType(newFee.getFeeAmount(), newFee
.getFeeStatus()));
assertFeeChangeType(FeeChangeType.AMOUNT_UPDATED, feeToChange);
}
@Test
public void testAmountFeeBOUpdateChangeTypeSetsStatusUpdated() throws Exception {
AmountFeeBO feeToChange = createAmountFeeToTestChangeFeeType();
AmountFeeBO newFee = createAmountFeeToTestChangeFeeType();
newFee.updateStatus(FeeStatus.INACTIVE);
feeToChange.updateFeeChangeType(feeToChange.calculateNewFeeChangeType(newFee.getFeeAmount(), newFee
.getFeeStatus()));
assertFeeChangeType(FeeChangeType.STATUS_UPDATED, feeToChange);
}
@Test
public void testAmountFeeBOUpdateChangeTypeSetsAmountAndStatusUpdated() throws Exception {
AmountFeeBO feeToChange = createAmountFeeToTestChangeFeeType();
AmountFeeBO newFee = (AmountFeeBO) createPeriodicAmountFee("fee", FeeCategory.ALLCUSTOMERS, "2000", true,
createMeeting());
newFee.updateStatus(FeeStatus.INACTIVE);
feeToChange.updateFeeChangeType(feeToChange.calculateNewFeeChangeType(newFee.getFeeAmount(), newFee
.getFeeStatus()));
assertFeeChangeType(FeeChangeType.AMOUNT_AND_STATUS_UPDATED, feeToChange);
}
@Test
public void testRateFeeBOUpdateChangeTypeSetsNotUpdated() throws Exception {
RateFeeBO feeToChange = createRateFeeToTestChangeFeeType();
RateFeeBO newFee = createRateFeeToTestChangeFeeType();
feeToChange.updateFeeChangeType(feeToChange.calculateNewFeeChangeType(newFee.getRate(), newFee.getFeeStatus()));
assertFeeChangeType(FeeChangeType.NOT_UPDATED, feeToChange);
}
@Test
public void testRateFeeBOUpdateChangeTypeSetsAmountUpdated() throws Exception {
RateFeeBO feeToChange = createRateFeeToTestChangeFeeType();
RateFeeBO newFee = new RateFeeBO(TestUtils.makeUser(), "Customer Fee", new CategoryTypeEntity(
FeeCategory.CENTER), new FeeFrequencyTypeEntity(FeeFrequencyType.ONETIME), getGLCode("7"), 1.0,
new FeeFormulaEntity(FeeFormula.AMOUNT), false, new FeePaymentEntity(FeePayment.UPFRONT));
feeToChange.updateFeeChangeType(feeToChange.calculateNewFeeChangeType(newFee.getRate(), newFee.getFeeStatus()));
assertFeeChangeType(FeeChangeType.AMOUNT_UPDATED, feeToChange);
}
@Test
public void testRateFeeBOUpdateChangeTypeSetsStatusUpdated() throws Exception {
RateFeeBO feeToChange = createRateFeeToTestChangeFeeType();
RateFeeBO newFee = createRateFeeToTestChangeFeeType();
newFee.updateStatus(FeeStatus.INACTIVE);
feeToChange.updateFeeChangeType(feeToChange.calculateNewFeeChangeType(newFee.getRate(), newFee.getFeeStatus()));
assertFeeChangeType(FeeChangeType.STATUS_UPDATED, feeToChange);
}
@Test
public void testRateFeeBOUpdateChangeTypeSetsAmountAndStatusUpdated() throws Exception {
RateFeeBO feeToChange = createRateFeeToTestChangeFeeType();
RateFeeBO newFee = new RateFeeBO(TestUtils.makeUser(), "Customer Fee", new CategoryTypeEntity(
FeeCategory.CENTER), new FeeFrequencyTypeEntity(FeeFrequencyType.ONETIME), getGLCode("7"), 1.0,
new FeeFormulaEntity(FeeFormula.AMOUNT), false, new FeePaymentEntity(FeePayment.UPFRONT));
newFee.updateStatus(FeeStatus.INACTIVE);
feeToChange.updateFeeChangeType(feeToChange.calculateNewFeeChangeType(newFee.getRate(), newFee.getFeeStatus()));
assertFeeChangeType(FeeChangeType.AMOUNT_AND_STATUS_UPDATED, feeToChange);
}
private void assertFeeChangeType(FeeChangeType feeChangeType, FeeBO feeToChange) throws PropertyNotFoundException {
Assert.assertEquals(feeChangeType, feeToChange.getFeeChangeType());
}
private AmountFeeBO createAmountFeeToTestChangeFeeType() throws Exception, MeetingException {
return (AmountFeeBO) createPeriodicAmountFee("fee", FeeCategory.ALLCUSTOMERS, "1000", true, createMeeting());
}
private RateFeeBO createRateFeeToTestChangeFeeType() throws FeeException {
return new RateFeeBO(TestUtils.makeUser(), "Customer Fee", new CategoryTypeEntity(FeeCategory.CENTER),
new FeeFrequencyTypeEntity(FeeFrequencyType.ONETIME), getGLCode("7"), 2.0, new FeeFormulaEntity(
FeeFormula.AMOUNT), false, new FeePaymentEntity(FeePayment.UPFRONT));
}
private MeetingBO createMeeting() throws MeetingException {
return new MeetingBO(RecurrenceType.WEEKLY, Short.valueOf("2"), new Date(), MeetingType.PERIODIC_FEE);
}
}