/*
* 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.loan.struts.action;
import static java.util.Arrays.asList;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mifos.accounts.loan.util.helpers.RequestConstants.PERSPECTIVE;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mifos.accounts.loan.business.LoanBO;
import org.mifos.accounts.loan.business.service.LoanBusinessService;
import org.mifos.accounts.loan.business.service.OriginalScheduleInfoDto;
import org.mifos.accounts.loan.struts.actionforms.LoanAccountActionForm;
import org.mifos.accounts.loan.util.helpers.LoanConstants;
import org.mifos.accounts.loan.util.helpers.RepaymentScheduleInstallment;
import org.mifos.accounts.productdefinition.business.service.LoanPrdBusinessService;
import org.mifos.application.questionnaire.struts.QuestionnaireFlowAdapter;
import org.mifos.application.servicefacade.LoanAccountServiceFacade;
import org.mifos.application.servicefacade.LoanServiceFacade;
import org.mifos.customers.persistence.CustomerDao;
import org.mifos.framework.TestUtils;
import org.mifos.framework.exceptions.PageExpiredException;
import org.mifos.framework.util.helpers.Constants;
import org.mifos.framework.util.helpers.Flow;
import org.mifos.framework.util.helpers.FlowManager;
import org.mifos.platform.questionnaire.service.QuestionDetail;
import org.mifos.platform.questionnaire.service.QuestionGroupDetail;
import org.mifos.platform.questionnaire.service.QuestionGroupInstanceDetail;
import org.mifos.platform.questionnaire.service.QuestionType;
import org.mifos.platform.questionnaire.service.QuestionnaireServiceFacade;
import org.mifos.platform.questionnaire.service.SectionDetail;
import org.mifos.platform.questionnaire.service.SectionQuestionDetail;
import org.mifos.platform.questionnaire.service.dtos.ChoiceDto;
import org.mifos.platform.validations.Errors;
import org.mifos.security.util.UserContext;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class LoanAccountActionTest {
@Mock
private QuestionnaireServiceFacade questionnaireServiceFacade;
@Mock
private HttpServletRequest request;
@Mock
private HttpServletResponse response;
@Mock
private HttpSession session;
@Mock
private FlowManager flowManager;
@Mock
private ActionMapping mapping;
private LoanAccountAction loanAccountAction;
public static final String FLOW_KEY = "FlowKey";
@Mock
private LoanAccountActionForm form;
private Flow flow;
@Mock
private LoanPrdBusinessService loanPrdBusinessService;
@Mock
private LoanServiceFacade loanServiceFacade;
@Mock
private LoanAccountServiceFacade loanAccountServiceFacade;
@Mock
private UserContext userContext;
private Short localeId = new Short("1");
@Mock
private LoanBusinessService loanBusinessService;
@Mock
private CustomerDao customerDao;
@Mock
private QuestionnaireFlowAdapter createLoanQuestionnaire;
@Mock
private LoanBO loanBO;
@Before
public void setUp() throws PageExpiredException {
loanAccountAction = new LoanAccountAction(null, loanBusinessService, null, loanPrdBusinessService, null, null, null, null) {
@SuppressWarnings("unused")
@Override
LoanBO getLoan(Integer loanId) {
return loanBO;
}
@Override
protected UserContext getUserContext(@SuppressWarnings("unused") HttpServletRequest request) {
return userContext;
}
@Override
QuestionnaireFlowAdapter getCreateLoanQuestionnaire() {
return createLoanQuestionnaire;
}
};
loanAccountAction.setLoanServiceFacade(loanServiceFacade);
loanAccountAction.setLoanAccountServiceFacade(loanAccountServiceFacade);
loanAccountAction.setCustomerDao(customerDao);
when(request.getAttribute(Constants.CURRENTFLOWKEY)).thenReturn(FLOW_KEY);
when(request.getSession()).thenReturn(session);
when(session.getAttribute(Constants.FLOWMANAGER)).thenReturn(flowManager);
flow = new Flow();
when(flowManager.getFlowWithValidation(FLOW_KEY)).thenReturn(flow);
when(userContext.getLocaleId()).thenReturn(localeId);
when(userContext.getPreferredLocale()).thenReturn(Locale.US);
}
@SuppressWarnings("unchecked")
@Test
public void shouldSetQuestionGroupInstanceDetailsInSession() throws PageExpiredException {
List<QuestionGroupInstanceDetail> instanceDetails = asList(getQuestionGroupInstanceDetail("QG1"), getQuestionGroupInstanceDetail("QG2"));
when(questionnaireServiceFacade.getQuestionGroupInstances(101, "View", "Loan")).thenReturn(instanceDetails);
loanAccountAction.setQuestionGroupInstances(questionnaireServiceFacade, request, 101);
assertThat((List<QuestionGroupInstanceDetail>) flow.getObjectFromSession("questionGroupInstances"), is(instanceDetails));
verify(questionnaireServiceFacade, times(1)).getQuestionGroupInstances(101, "View", "Loan");
verify(request, times(1)).getAttribute(Constants.CURRENTFLOWKEY);
verify(request, times(1)).getSession();
verify(session, times(1)).getAttribute(Constants.FLOWMANAGER);
}
@SuppressWarnings("unchecked")
@Test
public void shouldViewOriginalSchedule() throws Exception {
ActionForward viewOriginalScheduleForward = new ActionForward("viewOriginalSchedule");
int loanId = 1;
String loanAmount = "123";
List<RepaymentScheduleInstallment> installments = Collections.EMPTY_LIST;
java.sql.Date disbursementDate = new java.sql.Date(new DateTime().toDate().getTime());
OriginalScheduleInfoDto dto = mock(OriginalScheduleInfoDto.class);
when(dto.getOriginalLoanScheduleInstallment()).thenReturn(installments);
when(dto.getLoanAmount()).thenReturn(loanAmount);
when(dto.getDisbursementDate()).thenReturn(disbursementDate);
when(request.getParameter(LoanAccountAction.ACCOUNT_ID)).thenReturn(String.valueOf(loanId));
when(loanServiceFacade.retrieveOriginalLoanSchedule(loanId)).thenReturn(dto);
when(mapping.findForward("viewOriginalSchedule")).thenReturn(viewOriginalScheduleForward);
ActionForward forward = loanAccountAction.viewOriginalSchedule(mapping, form, request, response);
assertThat(forward, is(viewOriginalScheduleForward));
verify(request).getParameter(LoanAccountAction.ACCOUNT_ID);
verify(loanServiceFacade).retrieveOriginalLoanSchedule(loanId);
verify(dto).getOriginalLoanScheduleInstallment();
verify(dto).getLoanAmount();
verify(dto).getDisbursementDate();
verify(mapping).findForward("viewOriginalSchedule");
}
@Test
public void captureQuestionResponses() throws Exception {
String redoLoan = "redoLoan";
when(form.getPerspective()).thenReturn(redoLoan);
ActionErrors errors = mock(ActionErrors.class);
ActionForward forward = mock(ActionForward.class);
when(createLoanQuestionnaire.validateResponses(request, form)).thenReturn(errors);
when(errors.isEmpty()).thenReturn(true);
when(createLoanQuestionnaire.rejoinFlow(mapping)).thenReturn(forward);
loanAccountAction.captureQuestionResponses(mapping, form, request, response);
verify(request,times(1)).setAttribute(eq(LoanConstants.METHODCALLED), eq("captureQuestionResponses"));
verify(request,times(1)).setAttribute(PERSPECTIVE, redoLoan);
verify(createLoanQuestionnaire).rejoinFlow(mapping);
}
@Test
public void getLoanRepaymentScheduleShouldCalculateExtraInterest() throws Exception {
when(loanBusinessService.computeExtraInterest(eq(loanBO), Matchers.<Date>any())).thenReturn(new Errors());
when(request.getParameter("accountId")).thenReturn("1");
when(loanServiceFacade.retrieveOriginalLoanSchedule(Matchers.<Integer>any())).
thenReturn(new OriginalScheduleInfoDto("100", new Date(), Collections.<RepaymentScheduleInstallment>emptyList()));
loanAccountAction.getLoanRepaymentSchedule(mapping, form, request, response);
verify(loanBusinessService, times(1)).computeExtraInterest(Matchers.<LoanBO>any(), Matchers.<Date>any());
}
@Test
public void getLoanRepaymentScheduleShouldValidateViewDate() throws Exception {
ActionForward getLoanScheduleFailure = new ActionForward("getLoanRepaymentScheduleFailure");
java.sql.Date extraInterestDate = TestUtils.getSqlDate(10, 7, 2010);
Errors errors = new Errors();
errors.addError(LoanConstants.CANNOT_VIEW_REPAYMENT_SCHEDULE, new String[] {extraInterestDate.toString()});
when(loanBusinessService.computeExtraInterest(loanBO, extraInterestDate)).thenReturn(errors);
when(form.getScheduleViewDateValue(Locale.US)).thenReturn(extraInterestDate);
when(request.getParameter("accountId")).thenReturn("1");
when(mapping.findForward("getLoanRepaymentScheduleFailure")).thenReturn(getLoanScheduleFailure);
when(loanServiceFacade.retrieveOriginalLoanSchedule(Matchers.<Integer>any())).
thenReturn(new OriginalScheduleInfoDto("100", new Date(), Collections.<RepaymentScheduleInstallment>emptyList()));
ActionForward forward = loanAccountAction.getLoanRepaymentSchedule(mapping, form, request, response);
assertThat(forward, is(getLoanScheduleFailure));
verify(form).resetScheduleViewDate();
}
private QuestionGroupInstanceDetail getQuestionGroupInstanceDetail(String questionGroupTitle) {
QuestionGroupInstanceDetail detail = new QuestionGroupInstanceDetail();
detail.setDateCompleted(Calendar.getInstance().getTime());
detail.setQuestionGroupDetail(getQuestionGroupDetail(questionGroupTitle, asList("red", "green", "blue")));
return detail;
}
private QuestionGroupDetail getQuestionGroupDetail(String title, List<String> answerChoices) {
QuestionGroupDetail questionGroupDetail = new QuestionGroupDetail();
questionGroupDetail.setTitle(title);
questionGroupDetail.setId(123);
questionGroupDetail.setSectionDetails(asList(getSectionDetail("Section1", "Question1", answerChoices)));
return questionGroupDetail;
}
private SectionDetail getSectionDetail(String name, String title, List<String> answerChoices) {
SectionDetail sectionDetail = new SectionDetail();
sectionDetail.setName(name);
QuestionDetail questionDetail = new QuestionDetail(111, title, QuestionType.SINGLE_SELECT, true, true);
List<ChoiceDto> choiceDtos = new ArrayList<ChoiceDto>();
for (String answerChoice : answerChoices) {
choiceDtos.add(new ChoiceDto(answerChoice));
}
questionDetail.setAnswerChoices(choiceDtos);
sectionDetail.setQuestionDetails(asList(new SectionQuestionDetail(questionDetail, true)));
return sectionDetail;
}
}