/*
* 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.savings.persistence;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mifos.framework.util.helpers.IntegrationTestObjectMother.sampleBranchOffice;
import static org.mifos.framework.util.helpers.IntegrationTestObjectMother.testUser;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.joda.time.DateTime;
import org.joda.time.DateTimeUtils;
import org.joda.time.LocalDate;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.mifos.accounts.business.AccountActionDateEntity;
import org.mifos.accounts.business.AccountBO;
import org.mifos.accounts.productdefinition.business.SavingsOfferingBO;
import org.mifos.accounts.savings.business.SavingsBO;
import org.mifos.accounts.savings.business.SavingsScheduleEntity;
import org.mifos.application.holiday.business.Holiday;
import org.mifos.application.holiday.persistence.HolidayDao;
import org.mifos.application.holiday.util.helpers.RepaymentRuleTypes;
import org.mifos.application.master.business.MifosCurrency;
import org.mifos.application.meeting.business.MeetingBO;
import org.mifos.application.meeting.util.helpers.WeekDay;
import org.mifos.application.servicefacade.ApplicationContextProvider;
import org.mifos.calendar.DayOfWeek;
import org.mifos.config.FiscalCalendarRules;
import org.mifos.customers.center.business.CenterBO;
import org.mifos.customers.client.business.ClientBO;
import org.mifos.customers.group.business.GroupBO;
import org.mifos.domain.builders.CenterBuilder;
import org.mifos.domain.builders.ClientBuilder;
import org.mifos.domain.builders.GroupBuilder;
import org.mifos.domain.builders.MeetingBuilder;
import org.mifos.domain.builders.SavingsAccountBuilder;
import org.mifos.domain.builders.SavingsProductBuilder;
import org.mifos.dto.domain.HolidayDetails;
import org.mifos.framework.MifosIntegrationTestCase;
import org.mifos.framework.TestUtils;
import org.mifos.framework.util.StandardTestingService;
import org.mifos.framework.util.helpers.IntegrationTestObjectMother;
import org.mifos.framework.util.helpers.Money;
import org.mifos.service.test.TestMode;
import org.mifos.test.framework.util.DatabaseCleaner;
import org.springframework.beans.factory.annotation.Autowired;
/**
* FIXME - completely rewrite/fix these tests
*/
public class SavingsScheduleIntegrationTest extends MifosIntegrationTestCase {
@Autowired
private DatabaseCleaner databaseCleaner;
private static MifosCurrency oldDefaultCurrency;
private FiscalCalendarRules fiscalCalendarRules = new FiscalCalendarRules();
private List<WeekDay> savedWorkingDays = fiscalCalendarRules.getWorkingDays();
private MeetingBO meeting;
private CenterBO center;
private GroupBO group;
private ClientBO client;
private SavingsOfferingBO savingsProduct;
private SavingsBO savingsAccount;
private int savingsDueDayOfWeek;
private DateTime expectedFirstDepositDate;
@BeforeClass
public static void initialiseHibernateUtil() {
oldDefaultCurrency = Money.getDefaultCurrency();
Money.setDefaultCurrency(TestUtils.RUPEE);
new StandardTestingService().setTestMode(TestMode.INTEGRATION);
}
@AfterClass
public static void resetCurrency() {
Money.setDefaultCurrency(oldDefaultCurrency);
}
@Before
public void setupDates() {
savingsDueDayOfWeek = DayOfWeek.monday();
//First Monday on or after today
expectedFirstDepositDate = new DateTime().withDayOfWeek(savingsDueDayOfWeek);
if (expectedFirstDepositDate.isBefore(new DateTime())) {
expectedFirstDepositDate = expectedFirstDepositDate.plusWeeks(1);
}
}
@Before
public void cleanDatabaseTables() {
databaseCleaner.clean();
fiscalCalendarRules.setWorkingDays("MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY");
}
@After
public void cleanDatabaseTablesAfterTest() {
// NOTE: - only added to stop older integration tests failing due to brittleness
databaseCleaner.clean();
DateTimeUtils.setCurrentMillisSystem();
fiscalCalendarRules.setWorkingDays(weekDaysToPropertyString(savedWorkingDays));
}
@Ignore
@Test
public void createWeeklySavingScheduleSecondInstallmentFallsInMoratorium() throws Exception {
buildAndPersistHoliday(expectedFirstDepositDate.plusWeeks(1), expectedFirstDepositDate.plusWeeks(1),
RepaymentRuleTypes.REPAYMENT_MORATORIUM);
createClientSavingsAccount();
short installmentId = 1;
DateTime installmentDate = expectedFirstDepositDate;
for (AccountActionDateEntity accountActionDate : getActionDatesSortedByDate(savingsAccount)) {
SavingsScheduleEntity scheduleEntity = (SavingsScheduleEntity) accountActionDate;
assertThat(scheduleEntity.getInstallmentId(), is(installmentId));
if (installmentId < 2) {
assertThat(new LocalDate(scheduleEntity.getActionDate()),
is(new LocalDate(installmentDate.toDate())));
} else { // second and following dates pushed out one week.
assertThat(new LocalDate(scheduleEntity.getActionDate()),
is(new LocalDate(installmentDate.plusWeeks(1).toDate())));
}
assertThat(scheduleEntity.getDeposit().getAmountDoubleValue(), is(13.0));
installmentId++;
installmentDate = installmentDate.plusWeeks(1);
}
}
@Ignore
@Test
public void createWeeklySavingScheduleSecondInstallmentFallsInNextMeetingHoliday() throws Exception {
buildAndPersistHoliday(expectedFirstDepositDate.plusWeeks(1), expectedFirstDepositDate.plusWeeks(1),
RepaymentRuleTypes.NEXT_MEETING_OR_REPAYMENT);
createClientSavingsAccount();
short installmentId = 1;
DateTime installmentDate = expectedFirstDepositDate;
for (AccountActionDateEntity accountActionDate : getActionDatesSortedByDate(savingsAccount)) {
SavingsScheduleEntity scheduleEntity = (SavingsScheduleEntity) accountActionDate;
assertThat(scheduleEntity.getInstallmentId(), is(installmentId));
if (installmentId == 2) { // only second installment pushed out one week.
assertThat(new LocalDate(scheduleEntity.getActionDate()),
is(new LocalDate(installmentDate.plusWeeks(1).toDate())));
} else {
assertThat(new LocalDate(scheduleEntity.getActionDate()),
is(new LocalDate(installmentDate.toDate())));
}
assertThat(scheduleEntity.getDeposit().getAmountDoubleValue(), is(13.0));
installmentId++;
installmentDate = installmentDate.plusWeeks(1);
}
}
@Ignore
@Test
public void createWeeklySavingScheduleSecondInstallmentFallsInNextWorkingDayHoliday() throws Exception {
// One-day holiday on the second deposit date, Monday
buildAndPersistHoliday(expectedFirstDepositDate.plusWeeks(1), expectedFirstDepositDate.plusWeeks(1),
RepaymentRuleTypes.NEXT_WORKING_DAY);
createClientSavingsAccount();
short installmentId = 1;
DateTime installmentDate = expectedFirstDepositDate;
for (AccountActionDateEntity accountActionDate : getActionDatesSortedByDate(savingsAccount)) {
SavingsScheduleEntity scheduleEntity = (SavingsScheduleEntity) accountActionDate;
assertThat(scheduleEntity.getInstallmentId(), is(installmentId));
if (installmentId == 2) {
assertThat(new LocalDate(scheduleEntity.getActionDate()),
is(new LocalDate(installmentDate.plusDays(1).toDate()))); //Tuesday after holiday
} else {
assertThat(new LocalDate(scheduleEntity.getActionDate()),
is(new LocalDate(installmentDate.toDate())));
}
assertThat(scheduleEntity.getDeposit().getAmountDoubleValue(), is(13.0));
installmentId++;
installmentDate = installmentDate.plusWeeks(1);
}
}
@Ignore
@Test
public void createWeeklySavingScheduleNoHoliday() throws Exception {
createClientSavingsAccount();
short installmentId = 1;
DateTime installmentDate = expectedFirstDepositDate;
for (AccountActionDateEntity accountActionDate : getActionDatesSortedByDate(savingsAccount)) {
SavingsScheduleEntity scheduleEntity = (SavingsScheduleEntity) accountActionDate;
assertThat(new LocalDate(scheduleEntity.getActionDate()),
is(new LocalDate(installmentDate.toDate())));
assertThat(scheduleEntity.getDeposit().getAmountDoubleValue(), is(13.0));
installmentId++;
installmentDate = installmentDate.plusWeeks(1);
}
}
private String weekDaysToPropertyString(List<WeekDay> weekDays) {
String propertyString = "";
Boolean first = true;
for (WeekDay day : weekDays) {
if (!first) {
propertyString = propertyString + ",";
} else {
first = false;
}
propertyString = propertyString + day.toString();
}
return propertyString;
}
public void createClientSavingsAccount() throws Exception {
meeting = new MeetingBuilder().customerMeeting().weekly().every(1).withStartDate(expectedFirstDepositDate).build();
IntegrationTestObjectMother.saveMeeting(meeting);
center = new CenterBuilder().with(meeting).withName("Center").with(sampleBranchOffice())
.withLoanOfficer(testUser()).build();
IntegrationTestObjectMother.createCenter(center, meeting);
group = new GroupBuilder().withMeeting(meeting).withName("Group").withOffice(sampleBranchOffice())
.withLoanOfficer(testUser()).withParentCustomer(center).build();
IntegrationTestObjectMother.createGroup(group, meeting);
client = new ClientBuilder().withMeeting(meeting).withName("Client 1").withOffice(sampleBranchOffice())
.withLoanOfficer(testUser()).withParentCustomer(group).buildForIntegrationTests();
IntegrationTestObjectMother.createClient(client, meeting);
savingsProduct = new SavingsProductBuilder().mandatory().appliesToClientsOnly().buildForIntegrationTests();
HolidayDao holidayDao = ApplicationContextProvider.getBean(HolidayDao.class);
List<Holiday> holidays = holidayDao.findAllHolidaysThisYearAndNext(client.getOfficeId());
savingsAccount = new SavingsAccountBuilder().withSavingsProduct(savingsProduct)
.withCustomer(client)
.with(holidays)
.build();
IntegrationTestObjectMother.saveSavingsProductAndAssociatedSavingsAccounts(savingsProduct, savingsAccount);
}
private List<AccountActionDateEntity> getActionDatesSortedByDate(AccountBO customerAccount) {
List<AccountActionDateEntity> sortedList = new ArrayList<AccountActionDateEntity>();
sortedList.addAll(customerAccount.getAccountActionDates());
Collections.sort(sortedList);
return sortedList;
}
private void buildAndPersistHoliday (DateTime start, DateTime through, RepaymentRuleTypes rule) throws Exception {
HolidayDetails holidayDetails = new HolidayDetails("testHoliday", start.toDate(), through.toDate(), rule.getValue());
List<Short> officeIds = new LinkedList<Short>();
officeIds.add((short)1);
IntegrationTestObjectMother.createHoliday(holidayDetails, officeIds);
}
}