/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.fp.document; import static org.kuali.kfs.sys.KualiTestAssertionUtils.assertEquality; import static org.kuali.kfs.sys.KualiTestAssertionUtils.assertInequality; import static org.kuali.kfs.sys.fixture.AccountingLineFixture.LINE5; import static org.kuali.kfs.sys.fixture.UserNameFixture.dfogle; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.coa.service.AccountingPeriodService; import org.kuali.kfs.fp.businessobject.VoucherSourceAccountingLine; import org.kuali.kfs.sys.ConfigureContext; import org.kuali.kfs.sys.DocumentTestUtils; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.businessobject.SourceAccountingLine; import org.kuali.kfs.sys.businessobject.TargetAccountingLine; import org.kuali.kfs.sys.context.KualiTestBase; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.kfs.sys.document.AccountingDocument; import org.kuali.kfs.sys.document.AccountingDocumentTestUtils; import org.kuali.kfs.sys.document.Correctable; import org.kuali.kfs.sys.document.workflow.WorkflowTestUtils; import org.kuali.kfs.sys.fixture.AccountingLineFixture; import org.kuali.kfs.sys.monitor.ChangeMonitor; import org.kuali.kfs.sys.monitor.FinancialSystemDocumentStatusMonitor; import org.kuali.kfs.sys.monitor.DocumentWorkflowStatusMonitor; import org.kuali.rice.core.api.util.type.KualiDecimal; import org.kuali.rice.kew.api.document.DocumentStatus; import org.kuali.rice.kns.service.DataDictionaryService; import org.kuali.rice.kns.service.TransactionalDocumentDictionaryService; import org.kuali.rice.krad.document.Copyable; import org.kuali.rice.krad.document.Document; import org.kuali.rice.krad.service.DocumentService; import org.kuali.rice.krad.util.ObjectUtils; /** * This class is used to test JournalVoucherDocument. */ @ConfigureContext(session = dfogle) public class JournalVoucherDocumentTest extends KualiTestBase { public static final Class<JournalVoucherDocument> DOCUMENT_CLASS = JournalVoucherDocument.class; private JournalVoucherDocument buildDocument() throws Exception { // put accounting lines into document parameter for later JournalVoucherDocument document = (JournalVoucherDocument) getDocumentParameterFixture(); StackTraceElement[] trace = Thread.currentThread().getStackTrace(); document.getDocumentHeader().setDocumentDescription(StringUtils.abbreviate("Unit Test doc for "+trace[3].getMethodName(), SpringContext.getBean(DataDictionaryService.class).getAttributeMaxLength(document.getDocumentHeader().getClass(), "documentDescription"))); document.getDocumentHeader().setExplanation(StringUtils.abbreviate("Unit test created document for "+trace[3].getClassName()+"."+trace[3].getMethodName(), SpringContext.getBean(DataDictionaryService.class).getAttributeMaxLength(document.getDocumentHeader().getClass(), "explanation"))); // set accountinglines to document for (AccountingLineFixture sourceFixture : getSourceAccountingLineParametersFromFixtures()) { sourceFixture.addAsVoucherSourceTo(document); } document.setBalanceTypeCode(KFSConstants.BALANCE_TYPE_ACTUAL); return document; } /** * Had to override b/c there are too many differences between the JV and the standard document structure (i.e. GLPEs generate * differently, routing isn't standard, etc). * * @see org.kuali.rice.krad.document.AccountingDocumentTestBase#testConvertIntoCopy() */ @ConfigureContext(session = dfogle, shouldCommitTransactions = true) public void testConvertIntoCopy() throws Exception { // save the original doc, wait for status change AccountingDocument document = buildDocument(); SpringContext.getBean(DocumentService.class).routeDocument(document, "saving copy source document", null); // collect some preCopy data String preCopyId = document.getDocumentNumber(); String preCopyCopiedFromId = document.getDocumentHeader().getDocumentTemplateNumber(); int preCopyPECount = document.getGeneralLedgerPendingEntries().size(); // int preCopyNoteCount = document.getDocumentHeader().getNotes().size(); List preCopySourceLines = (List) ObjectUtils.deepCopy((Serializable)document.getSourceAccountingLines()); List preCopyTargetLines = (List) ObjectUtils.deepCopy((Serializable)document.getTargetAccountingLines()); // validate preCopy state assertNotNull(preCopyId); assertNull(preCopyCopiedFromId); assertEquals(1, preCopyPECount); // assertEquals(0, preCopyNoteCount); // do the copy ((Copyable) document).toCopy(); // compare to preCopy state String postCopyId = document.getDocumentNumber(); assertFalse(postCopyId.equals(preCopyId)); // verify that docStatus has changed // pending entries should be cleared int postCopyPECount = document.getGeneralLedgerPendingEntries().size(); assertEquals(0, postCopyPECount); // TODO: revisit this is it still needed // count 1 note, compare to "copied" text // int postCopyNoteCount = document.getDocumentHeader().getNotes().size(); // assertEquals(1, postCopyNoteCount); // DocumentNote note = document.getDocumentHeader().getNote(0); // assertTrue(note.getFinancialDocumentNoteText().indexOf("copied from") != -1); // copiedFrom should be equal to old id String copiedFromId = document.getDocumentHeader().getDocumentTemplateNumber(); assertEquals(preCopyId, copiedFromId); // accounting lines should be have different docHeaderIds but same amounts List postCopySourceLines = document.getSourceAccountingLines(); assertEquals(preCopySourceLines.size(), postCopySourceLines.size()); for (int i = 0; i < preCopySourceLines.size(); ++i) { SourceAccountingLine preCopyLine = (SourceAccountingLine) preCopySourceLines.get(i); SourceAccountingLine postCopyLine = (SourceAccountingLine) postCopySourceLines.get(i); assertInequality(preCopyLine.getDocumentNumber(), postCopyLine.getDocumentNumber()); assertEquality(preCopyLine.getAmount(), postCopyLine.getAmount()); } List postCopyTargetLines = document.getTargetAccountingLines(); assertEquals(preCopyTargetLines.size(), postCopyTargetLines.size()); for (int i = 0; i < preCopyTargetLines.size(); ++i) { TargetAccountingLine preCopyLine = (TargetAccountingLine) preCopyTargetLines.get(i); TargetAccountingLine postCopyLine = (TargetAccountingLine) postCopyTargetLines.get(i); assertInequality(preCopyLine.getDocumentNumber(), postCopyLine.getDocumentNumber()); assertEquality(preCopyLine.getAmount(), postCopyLine.getAmount()); } } /** * Had to override b/c there are too many differences between the JV and the standard document structure (i.e. GLPEs generate * differently, routing isn't standard, etc). * * @see org.kuali.rice.krad.document.AccountingDocumentTestBase#testConvertIntoErrorCorrection() */ @ConfigureContext(session = dfogle, shouldCommitTransactions = true) public void testConvertIntoErrorCorrection() throws Exception { AccountingDocument document = buildDocument(); // replace the broken sourceLines with one that lets the test succeed KualiDecimal balance = new KualiDecimal("21.12"); ArrayList sourceLines = new ArrayList(); { VoucherSourceAccountingLine sourceLine = new VoucherSourceAccountingLine(); sourceLine.setDocumentNumber(document.getDocumentNumber()); sourceLine.setSequenceNumber(new Integer(1)); sourceLine.setChartOfAccountsCode("BL"); sourceLine.setAccountNumber("1031400"); sourceLine.setFinancialObjectCode("1663"); sourceLine.setAmount(balance); sourceLine.setObjectTypeCode("AS"); sourceLine.setBalanceTypeCode("AC"); sourceLine.setDebitCreditCode(KFSConstants.GL_DEBIT_CODE); sourceLine.refresh(); sourceLines.add(sourceLine); } document.setSourceAccountingLines(sourceLines); String documentHeaderId = document.getDocumentNumber(); // route the original doc, wait for status change SpringContext.getBean(DocumentService.class).routeDocument(document, "saving errorCorrection source document", null); // jv docs go straight to final WorkflowTestUtils.waitForDocumentApproval(documentHeaderId); document = (AccountingDocument) SpringContext.getBean(DocumentService.class).getByDocumentHeaderId(documentHeaderId); // collect some preCorrect data String preCorrectId = document.getDocumentNumber(); String preCorrectCorrectsId = document.getFinancialSystemDocumentHeader().getFinancialDocumentInErrorNumber(); int preCorrectPECount = document.getGeneralLedgerPendingEntries().size(); // int preCorrectNoteCount = document.getDocumentHeader().getNotes().size(); DocumentStatus preCorrectStatus = document.getDocumentHeader().getWorkflowDocument().getStatus(); ArrayList preCorrectSourceLines = (ArrayList) ObjectUtils.deepCopy(new ArrayList(document.getSourceAccountingLines())); ArrayList preCorrectTargetLines = (ArrayList) ObjectUtils.deepCopy(new ArrayList(document.getTargetAccountingLines())); // validate preCorrect state assertNotNull("Pre-correct document number should not be null.",preCorrectId); assertNull("preCorrectCorrectsId should have been null",preCorrectCorrectsId); // assertEquals(0, preCorrectNoteCount); assertEquals("Document status is incorrect", DocumentStatus.FINAL, preCorrectStatus); // do the copy ((Correctable) document).toErrorCorrection(); // compare to preCorrect state String postCorrectId = document.getDocumentNumber(); assertFalse("document number should be different before and after correction. Both were: " + postCorrectId, postCorrectId.equals(preCorrectId)); // pending entries should be cleared int postCorrectPECount = document.getGeneralLedgerPendingEntries().size(); assertEquals("pending entry count should have been zero after correction",0, postCorrectPECount); // TODO: revisit this is it still needed // count 1 note, compare to "correction" text // int postCorrectNoteCount = document.getDocumentHeader().getNotes().size(); // assertEquals(1, postCorrectNoteCount); // DocumentNote note = document.getDocumentHeader().getNote(0); // assertTrue(note.getFinancialDocumentNoteText().indexOf("correction") != -1); // correctsId should be equal to old id String correctsId = document.getFinancialSystemDocumentHeader().getFinancialDocumentInErrorNumber(); assertEquals(preCorrectId, correctsId); // accounting lines should have sign reversed on amounts List postCorrectSourceLines = document.getSourceAccountingLines(); assertEquals(preCorrectSourceLines.size(), postCorrectSourceLines.size()); for (int i = 0; i < preCorrectSourceLines.size(); ++i) { SourceAccountingLine preCorrectLine = (SourceAccountingLine) preCorrectSourceLines.get(i); SourceAccountingLine postCorrectLine = (SourceAccountingLine) postCorrectSourceLines.get(i); assertEquality(postCorrectId, postCorrectLine.getDocumentNumber()); assertEquality(preCorrectLine.getAmount(), postCorrectLine.getAmount()); assertEquality(postCorrectLine.getDebitCreditCode(), KFSConstants.GL_CREDIT_CODE); } List postCorrectTargetLines = document.getTargetAccountingLines(); assertEquals(preCorrectTargetLines.size(), postCorrectTargetLines.size()); for (int i = 0; i < preCorrectTargetLines.size(); ++i) { TargetAccountingLine preCorrectLine = (TargetAccountingLine) preCorrectTargetLines.get(i); TargetAccountingLine postCorrectLine = (TargetAccountingLine) postCorrectTargetLines.get(i); assertEquality(postCorrectId, postCorrectLine.getDocumentNumber()); assertEquality(preCorrectLine.getAmount().negated(), postCorrectLine.getAmount()); } } /** * Override b/c the status changing is flakey with this doc b/c routing is special (goes straight to final). * * @see org.kuali.rice.krad.document.DocumentTestBase#testRouteDocument() */ // @RelatesTo(JiraIssue.KULRNE4926) @ConfigureContext(session = dfogle, shouldCommitTransactions = true) public void testRouteDocument() throws Exception { // save the original doc, wait for status change Document document = buildDocument(); assertFalse(DocumentStatus.ENROUTE.equals(document.getDocumentHeader().getWorkflowDocument().getStatus())); SpringContext.getBean(DocumentService.class).routeDocument(document, "saving copy source document", null); // jv docs go sttraight to final WorkflowTestUtils.waitForDocumentApproval(document.getDocumentNumber()); // also check the Kuali (not Workflow) document status FinancialSystemDocumentStatusMonitor statusMonitor = new FinancialSystemDocumentStatusMonitor(SpringContext.getBean(DocumentService.class), document.getDocumentHeader().getDocumentNumber(), KFSConstants.DocumentStatusCodes.APPROVED); assertTrue(ChangeMonitor.waitUntilChange(statusMonitor, 30, 5)); } private Document getDocumentParameterFixture() throws Exception { return DocumentTestUtils.createDocument(SpringContext.getBean(DocumentService.class), JournalVoucherDocument.class); } private List<AccountingLineFixture> getTargetAccountingLineParametersFromFixtures() { ArrayList list = new ArrayList(); return list; } private List<AccountingLineFixture> getSourceAccountingLineParametersFromFixtures() { List<AccountingLineFixture> list = new ArrayList<AccountingLineFixture>(); list.add(LINE5); return list; } public final void testAddAccountingLine() throws Exception { List<SourceAccountingLine> sourceLines = generateSouceAccountingLines(); List<TargetAccountingLine> targetLines = generateTargetAccountingLines(); int expectedSourceTotal = sourceLines.size(); int expectedTargetTotal = targetLines.size(); JournalVoucherDocument document = DocumentTestUtils.createDocument(SpringContext.getBean(DocumentService.class), DOCUMENT_CLASS); document.setBalanceTypeCode(KFSConstants.BALANCE_TYPE_ACTUAL); AccountingDocumentTestUtils.testAddAccountingLine(document, sourceLines, targetLines, expectedSourceTotal, expectedTargetTotal); } public final void testGetNewDocument() throws Exception { AccountingDocumentTestUtils.testGetNewDocument_byDocumentClass(DOCUMENT_CLASS, SpringContext.getBean(DocumentService.class)); } public final void testConvertIntoCopy_copyDisallowed() throws Exception { AccountingDocumentTestUtils.testConvertIntoCopy_copyDisallowed(buildDocument(), SpringContext.getBean(DataDictionaryService.class)); } public final void testConvertIntoErrorCorrection_documentAlreadyCorrected() throws Exception { AccountingDocumentTestUtils.testConvertIntoErrorCorrection_documentAlreadyCorrected(buildDocument(), SpringContext.getBean(TransactionalDocumentDictionaryService.class)); } public final void testConvertIntoErrorCorrection_errorCorrectionDisallowed() throws Exception { AccountingDocumentTestUtils.testConvertIntoErrorCorrection_errorCorrectionDisallowed(buildDocument(), SpringContext.getBean(DataDictionaryService.class)); } public final void testConvertIntoErrorCorrection_invalidYear() throws Exception { AccountingDocumentTestUtils.testConvertIntoErrorCorrection_invalidYear(buildDocument(), SpringContext.getBean(TransactionalDocumentDictionaryService.class), SpringContext.getBean(AccountingPeriodService.class)); } @ConfigureContext(session = dfogle, shouldCommitTransactions = true) public final void testSaveDocument() throws Exception { AccountingDocumentTestUtils.testSaveDocument(buildDocument(), SpringContext.getBean(DocumentService.class)); } // test util methods private List<SourceAccountingLine> generateSouceAccountingLines() throws Exception { List<SourceAccountingLine> sourceLines = new ArrayList<SourceAccountingLine>(); // set accountinglines to document for (AccountingLineFixture sourceFixture : getSourceAccountingLineParametersFromFixtures()) { sourceLines.add(sourceFixture.createSourceAccountingLine()); } return sourceLines; } private List<TargetAccountingLine> generateTargetAccountingLines() throws Exception { List<TargetAccountingLine> targetLines = new ArrayList<TargetAccountingLine>(); for (AccountingLineFixture targetFixture : getTargetAccountingLineParametersFromFixtures()) { targetLines.add(targetFixture.createTargetAccountingLine()); } return targetLines; } }