001: /*
002: * Copyright 2005-2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.kuali.module.financial.document;
017:
018: import static org.kuali.module.financial.document.AccountingDocumentTestUtils.approveDocument;
019: import static org.kuali.module.financial.document.AccountingDocumentTestUtils.routeDocument;
020: import static org.kuali.module.financial.document.AccountingDocumentTestUtils.testGetNewDocument_byDocumentClass;
021: import static org.kuali.test.fixtures.AccountingLineFixture.LINE2;
022: import static org.kuali.test.fixtures.AccountingLineFixture.LINE3;
023: import static org.kuali.test.fixtures.UserNameFixture.KHUNTLEY;
024: import static org.kuali.test.fixtures.UserNameFixture.RJWEISS;
025: import static org.kuali.test.fixtures.UserNameFixture.RORENFRO;
026:
027: import java.util.ArrayList;
028: import java.util.List;
029:
030: import org.kuali.core.document.Document;
031: import org.kuali.core.exceptions.DocumentAuthorizationException;
032: import org.kuali.core.exceptions.ValidationException;
033: import org.kuali.core.service.DataDictionaryService;
034: import org.kuali.core.service.DocumentService;
035: import org.kuali.core.service.TransactionalDocumentDictionaryService;
036: import org.kuali.core.util.GlobalVariables;
037: import org.kuali.core.util.KualiDecimal;
038: import org.kuali.kfs.KFSKeyConstants;
039: import org.kuali.kfs.bo.SourceAccountingLine;
040: import org.kuali.kfs.bo.TargetAccountingLine;
041: import org.kuali.kfs.context.KualiTestBase;
042: import org.kuali.kfs.context.SpringContext;
043: import org.kuali.kfs.document.AccountingDocument;
044: import org.kuali.test.ConfigureContext;
045: import org.kuali.test.DocumentTestUtils;
046: import org.kuali.test.fixtures.AccountingLineFixture;
047: import org.kuali.test.fixtures.UserNameFixture;
048: import org.kuali.test.suite.AnnotationTestSuite;
049: import org.kuali.test.suite.CrossSectionSuite;
050:
051: /**
052: * This class is used to test InternalBillingDocument.
053: */
054: @ConfigureContext(session=KHUNTLEY)
055: // @RelatesTo(RelatesTo.JiraIssue.KULRNE5908)
056: public class InternalBillingDocumentTest extends KualiTestBase {
057: public static final Class<InternalBillingDocument> DOCUMENT_CLASS = InternalBillingDocument.class;
058:
059: private Document getDocumentParameterFixture() throws Exception {
060: return DocumentTestUtils.createDocument(SpringContext
061: .getBean(DocumentService.class),
062: InternalBillingDocument.class);
063: }
064:
065: private List<AccountingLineFixture> getTargetAccountingLineParametersFromFixtures() {
066: List<AccountingLineFixture> list = new ArrayList<AccountingLineFixture>();
067: list.add(LINE2);
068: list.add(LINE3);
069: list.add(LINE2);
070: return list;
071: }
072:
073: private List<AccountingLineFixture> getSourceAccountingLineParametersFromFixtures() {
074: List<AccountingLineFixture> list = new ArrayList<AccountingLineFixture>();
075: list.add(LINE2);
076: list.add(LINE3);
077: list.add(LINE2);
078: return list;
079: }
080:
081: private int getExpectedPrePeCount() {
082: return 12;
083: }
084:
085: @ConfigureContext(session=KHUNTLEY,shouldCommitTransactions=true)
086: public final void testApprove_addAccessibleAccount_ChangingTotals()
087: throws Exception {
088: AccountingDocument retrieved;
089: AccountingDocument original;
090: String docId;
091:
092: // switch user to WESPRICE, build and route document with
093: // accountingLines
094: changeCurrentUser(getInitialUserName());
095: original = buildDocument();
096: routeDocument(original, SpringContext
097: .getBean(DocumentService.class));
098: docId = original.getDocumentNumber();
099:
100: // switch user to another user, add accountingLines for accounts not
101: // controlled by this user
102: changeCurrentUser(getTestUserName());
103: retrieved = (AccountingDocument) SpringContext.getBean(
104: DocumentService.class).getByDocumentHeaderId(docId);
105: retrieved
106: .addSourceAccountingLine(getSourceAccountingLineAccessibleAccount());
107: retrieved
108: .addTargetAccountingLine(getTargetAccountingLineAccessibleAccount());
109:
110: boolean failedAsExpected = false;
111: try {
112: approveDocument(retrieved, SpringContext
113: .getBean(DocumentService.class));
114: } catch (ValidationException e) {
115: failedAsExpected = true;
116: } catch (DocumentAuthorizationException dae) {
117: // this means that the workflow status didn't change in time for the check, so this is
118: // an expected exception
119: failedAsExpected = true;
120: }
121: assertTrue(failedAsExpected);
122: }
123:
124: @ConfigureContext(session=KHUNTLEY,shouldCommitTransactions=true)
125: public final void testApprove_addInaccessibleAccount_sourceLine()
126: throws Exception {
127: // switch user to WESPRICE, build and route document with
128: // accountingLines
129: AccountingDocument original;
130: AccountingDocument retrieved;
131: String docId;
132:
133: changeCurrentUser(getInitialUserName());
134: original = buildDocument();
135: routeDocument(original, SpringContext
136: .getBean(DocumentService.class));
137: docId = original.getDocumentNumber();
138:
139: // switch user to AHORNICK, add sourceAccountingLine for account not controlled by this user
140: // (and add a balancing targetAccountingLine for an accessible account)
141: changeCurrentUser(getTestUserName());
142: retrieved = (AccountingDocument) SpringContext.getBean(
143: DocumentService.class).getByDocumentHeaderId(docId);
144: retrieved
145: .addSourceAccountingLine(getSourceAccountingLineInaccessibleAccount());
146: retrieved
147: .addTargetAccountingLine(getTargetAccountingLineAccessibleAccount());
148:
149: // approve document, wait for failure b/c totals have changed
150: boolean failedAsExpected = false;
151: try {
152: approveDocument(retrieved, SpringContext
153: .getBean(DocumentService.class));
154: } catch (ValidationException e) {
155: failedAsExpected = true;
156: } catch (DocumentAuthorizationException dae) {
157: // this means that the workflow status didn't change in time for the check, so this is
158: // an expected exception
159: failedAsExpected = true;
160: }
161: assertTrue(failedAsExpected);
162: }
163:
164: @ConfigureContext(session=KHUNTLEY,shouldCommitTransactions=true)
165: public final void testApprove_addInaccessibleAccount_targetLine()
166: throws Exception {
167: AccountingDocument retrieved;
168: AccountingDocument original;
169: String docId;
170:
171: // switch user to WESPRICE, build and route document with
172: // accountingLines
173: changeCurrentUser(getInitialUserName());
174: original = buildDocument();
175: routeDocument(original, SpringContext
176: .getBean(DocumentService.class));
177: docId = original.getDocumentNumber();
178:
179: // switch user to AHORNICK, add targetAccountingLine for accounts not
180: // controlled by this user
181: // (and add a balancing sourceAccountingLine for an accessible account)
182: changeCurrentUser(getTestUserName());
183: retrieved = (AccountingDocument) SpringContext.getBean(
184: DocumentService.class).getByDocumentHeaderId(docId);
185: retrieved
186: .addTargetAccountingLine(getTargetAccountingLineInaccessibleAccount());
187: retrieved
188: .addSourceAccountingLine(getSourceAccountingLineAccessibleAccount());
189:
190: // approve document, wait for failure
191: boolean failedAsExpected = false;
192: try {
193: approveDocument(retrieved, SpringContext
194: .getBean(DocumentService.class));
195: } catch (ValidationException e) {
196: failedAsExpected = true;
197: } catch (DocumentAuthorizationException dae) {
198: // this means that the workflow status didn't change in time for the check, so this is
199: // an expected exception
200: failedAsExpected = true;
201: }
202: assertTrue(failedAsExpected);
203: }
204:
205: @ConfigureContext(session=KHUNTLEY,shouldCommitTransactions=true)
206: public final void testApprove_deleteAccessibleAccount()
207: throws Exception {
208: // switch user to WESPRICE, build and route document with
209: // accountingLines
210: AccountingDocument retrieved;
211: AccountingDocument original;
212: String docId;
213:
214: changeCurrentUser(getInitialUserName());
215: original = buildDocument();
216: routeDocument(original, SpringContext
217: .getBean(DocumentService.class));
218: docId = original.getDocumentNumber();
219:
220: // switch user to AHORNICK, delete sourceAccountingLine for accounts
221: // controlled by this user
222: // (and delete matching targetAccountingLine, for balance)
223: changeCurrentUser(getTestUserName());
224: retrieved = (AccountingDocument) SpringContext.getBean(
225: DocumentService.class).getByDocumentHeaderId(docId);
226: deleteSourceAccountingLine(retrieved, 0);
227: deleteTargetAccountingLine(retrieved, 0);
228:
229: // approve document, wait for failure b/c totals have changed
230: boolean failedAsExpected = false;
231: try {
232: approveDocument(retrieved, SpringContext
233: .getBean(DocumentService.class));
234: } catch (ValidationException e) {
235: failedAsExpected = true;
236: } catch (DocumentAuthorizationException dae) {
237: // this means that the workflow status didn't change in time for the check, so this is
238: // an expected exception
239: failedAsExpected = true;
240: }
241: assertTrue(failedAsExpected);
242: }
243:
244: @ConfigureContext(session=KHUNTLEY,shouldCommitTransactions=true)
245: public final void testApprove_deleteLastAccessibleAccount()
246: throws Exception {
247: // switch user to WESPRICE, build and route document with
248: // accountingLines
249: AccountingDocument retrieved;
250: AccountingDocument original;
251: String docId;
252:
253: changeCurrentUser(getInitialUserName());
254: original = buildDocument();
255: routeDocument(original, SpringContext
256: .getBean(DocumentService.class));
257: docId = original.getDocumentNumber();
258:
259: // switch user to AHORNICK, delete all accountingLines for that user
260: changeCurrentUser(getTestUserName());
261: retrieved = (AccountingDocument) SpringContext.getBean(
262: DocumentService.class).getByDocumentHeaderId(docId);
263: deleteSourceAccountingLine(retrieved, 2);
264: deleteSourceAccountingLine(retrieved, 0);
265:
266: deleteTargetAccountingLine(retrieved, 2);
267: deleteTargetAccountingLine(retrieved, 0);
268:
269: // approve document, wait for failure
270: boolean failedAsExpected = false;
271: try {
272: approveDocument(retrieved, SpringContext
273: .getBean(DocumentService.class));
274: } catch (ValidationException e) {
275: failedAsExpected = GlobalVariables
276: .getErrorMap()
277: .containsMessageKey(
278: KFSKeyConstants.ERROR_ACCOUNTINGLINE_LASTACCESSIBLE_DELETE);
279: } catch (DocumentAuthorizationException dae) {
280: // this means that the workflow status didn't change in time for the check, so this is
281: // an expected exception
282: failedAsExpected = true;
283: }
284: assertTrue(failedAsExpected);
285: }
286:
287: @AnnotationTestSuite(CrossSectionSuite.class)
288: @ConfigureContext(session=KHUNTLEY,shouldCommitTransactions=true)
289: public final void testApprove_updateAccessibleAccount()
290: throws Exception {
291: // switch user to WESPRICE, build and route document with
292: // accountingLines
293: AccountingDocument retrieved;
294: AccountingDocument original;
295: String docId;
296:
297: changeCurrentUser(getInitialUserName());
298: original = buildDocument();
299: routeDocument(original, SpringContext
300: .getBean(DocumentService.class));
301: docId = original.getDocumentNumber();
302:
303: // switch user to AHORNICK, update sourceAccountingLine for accounts
304: // controlled by this user
305: // (and delete update targetAccountingLine, for balance)
306: changeCurrentUser(getTestUserName());
307: retrieved = (AccountingDocument) SpringContext.getBean(
308: DocumentService.class).getByDocumentHeaderId(docId);
309:
310: // make sure totals don't change
311: KualiDecimal originalSourceLineAmt = retrieved
312: .getSourceAccountingLine(0).getAmount();
313: KualiDecimal originalTargetLineAmt = retrieved
314: .getTargetAccountingLine(0).getAmount();
315: KualiDecimal newSourceLineAmt = originalSourceLineAmt
316: .divide(new KualiDecimal(2));
317: KualiDecimal newTargetLineAmt = originalTargetLineAmt
318: .divide(new KualiDecimal(2));
319:
320: // update existing lines with new amount which equals orig divided by 2
321: updateSourceAccountingLine(retrieved, 0, newSourceLineAmt
322: .toString());
323: updateTargetAccountingLine(retrieved, 0, newTargetLineAmt
324: .toString());
325:
326: // add in new lines and change amounts
327: TargetAccountingLine newTargetLine = getTargetAccountingLineAccessibleAccount();
328: newTargetLine.setAmount(newTargetLineAmt);
329: SourceAccountingLine newSourceLine = getSourceAccountingLineAccessibleAccount();
330: newSourceLine.setAmount(newSourceLineAmt);
331: retrieved.addTargetAccountingLine(newTargetLine);
332: retrieved.addSourceAccountingLine(newSourceLine);
333:
334: try {
335: approveDocument(retrieved, SpringContext
336: .getBean(DocumentService.class));
337: } catch (DocumentAuthorizationException dae) {
338: // this means that the workflow status didn't change in time for the check, so this is
339: // an expected exception
340: }
341: }
342:
343: @ConfigureContext(session=KHUNTLEY,shouldCommitTransactions=true)
344: public final void testApprove_updateInaccessibleAccount_sourceLine()
345: throws Exception {
346: AccountingDocument retrieved;
347: AccountingDocument original;
348: String docId;
349:
350: // switch user to WESPRICE, build and route document with
351: // accountingLines
352: changeCurrentUser(getInitialUserName());
353: original = buildDocument();
354: routeDocument(original, SpringContext
355: .getBean(DocumentService.class));
356: docId = original.getDocumentNumber();
357:
358: // switch user to AHORNICK, update sourceAccountingLines for accounts
359: // not controlled by this user
360: // (and update matching accessible targetLine, for balance)
361: changeCurrentUser(getTestUserName());
362: retrieved = (AccountingDocument) SpringContext.getBean(
363: DocumentService.class).getByDocumentHeaderId(docId);
364: updateSourceAccountingLine(retrieved, 1, "3.14");
365: updateTargetAccountingLine(retrieved, 0, "3.14");
366:
367: // approve document, wait for failure
368: boolean failedAsExpected = false;
369: try {
370: approveDocument(retrieved, SpringContext
371: .getBean(DocumentService.class));
372: } catch (ValidationException e) {
373: failedAsExpected = GlobalVariables
374: .getErrorMap()
375: .containsMessageKey(
376: KFSKeyConstants.ERROR_ACCOUNTINGLINE_INACCESSIBLE_UPDATE);
377: } catch (DocumentAuthorizationException dae) {
378: // this means that the workflow status didn't change in time for the check, so this is
379: // an expected exception
380: failedAsExpected = true;
381: }
382: assertTrue(failedAsExpected);
383: }
384:
385: @ConfigureContext(session=KHUNTLEY,shouldCommitTransactions=true)
386: public final void testApprove_updateInaccessibleAccount_targetLine()
387: throws Exception {
388: // switch user to WESPRICE, build and route document with
389: // accountingLines
390: AccountingDocument retrieved;
391: AccountingDocument original;
392: String docId;
393:
394: changeCurrentUser(getInitialUserName());
395: original = buildDocument();
396: routeDocument(original, SpringContext
397: .getBean(DocumentService.class));
398: docId = original.getDocumentNumber();
399:
400: // switch user to AHORNICK, update targetAccountingLine for accounts
401: // not controlled by this user
402: // (and update matching accessible sourceLine, for balance)
403: changeCurrentUser(getTestUserName());
404: retrieved = (AccountingDocument) SpringContext.getBean(
405: DocumentService.class).getByDocumentHeaderId(docId);
406: updateTargetAccountingLine(retrieved, 1, "2.81");
407: updateSourceAccountingLine(retrieved, 0, "2.81");
408:
409: // approve document, wait for failure
410: boolean failedAsExpected = false;
411: try {
412: approveDocument(retrieved, SpringContext
413: .getBean(DocumentService.class));
414: } catch (ValidationException e) {
415: failedAsExpected = GlobalVariables
416: .getErrorMap()
417: .containsMessageKey(
418: KFSKeyConstants.ERROR_ACCOUNTINGLINE_INACCESSIBLE_UPDATE);
419: } catch (DocumentAuthorizationException dae) {
420: // this means that the workflow status didn't change in time for the check, so this is
421: // an expected exception
422: failedAsExpected = true;
423: }
424: assertTrue(failedAsExpected);
425: }
426:
427: public final void testAddAccountingLine() throws Exception {
428: List<SourceAccountingLine> sourceLines = generateSouceAccountingLines();
429: List<TargetAccountingLine> targetLines = generateTargetAccountingLines();
430: int expectedSourceTotal = sourceLines.size();
431: int expectedTargetTotal = targetLines.size();
432: AccountingDocumentTestUtils.testAddAccountingLine(
433: DocumentTestUtils
434: .createDocument(SpringContext
435: .getBean(DocumentService.class),
436: DOCUMENT_CLASS), sourceLines,
437: targetLines, expectedSourceTotal, expectedTargetTotal);
438: }
439:
440: public final void testGetNewDocument() throws Exception {
441: testGetNewDocument_byDocumentClass(DOCUMENT_CLASS,
442: SpringContext.getBean(DocumentService.class));
443: }
444:
445: public final void testConvertIntoCopy_copyDisallowed()
446: throws Exception {
447: AccountingDocumentTestUtils.testConvertIntoCopy_copyDisallowed(
448: buildDocument(), SpringContext
449: .getBean(DataDictionaryService.class));
450:
451: }
452:
453: public final void testConvertIntoErrorCorrection_documentAlreadyCorrected()
454: throws Exception {
455: AccountingDocumentTestUtils
456: .testConvertIntoErrorCorrection_documentAlreadyCorrected(
457: buildDocument(),
458: SpringContext
459: .getBean(TransactionalDocumentDictionaryService.class));
460: }
461:
462: public final void testConvertIntoErrorCorrection_errorCorrectionDisallowed()
463: throws Exception {
464: AccountingDocumentTestUtils
465: .testConvertIntoErrorCorrection_errorCorrectionDisallowed(
466: buildDocument(), SpringContext
467: .getBean(DataDictionaryService.class));
468: }
469:
470: @ConfigureContext(session=KHUNTLEY,shouldCommitTransactions=true)
471: public final void testConvertIntoErrorCorrection() throws Exception {
472: AccountingDocumentTestUtils
473: .testConvertIntoErrorCorrection(
474: buildDocument(),
475: getExpectedPrePeCount(),
476: SpringContext.getBean(DocumentService.class),
477: SpringContext
478: .getBean(TransactionalDocumentDictionaryService.class));
479: }
480:
481: @ConfigureContext(session=KHUNTLEY,shouldCommitTransactions=true)
482: public final void testRouteDocument() throws Exception {
483: AccountingDocumentTestUtils.testRouteDocument(buildDocument(),
484: SpringContext.getBean(DocumentService.class));
485: }
486:
487: @ConfigureContext(session=KHUNTLEY,shouldCommitTransactions=true)
488: public final void testSaveDocument() throws Exception {
489: AccountingDocumentTestUtils.testSaveDocument(buildDocument(),
490: SpringContext.getBean(DocumentService.class));
491: }
492:
493: @ConfigureContext(session=KHUNTLEY,shouldCommitTransactions=true)
494: public final void testConvertIntoCopy() throws Exception {
495: AccountingDocumentTestUtils.testConvertIntoCopy(
496: buildDocument(), SpringContext
497: .getBean(DocumentService.class),
498: getExpectedPrePeCount());
499: }
500:
501: // test util methods
502: private List<SourceAccountingLine> generateSouceAccountingLines()
503: throws Exception {
504: List<SourceAccountingLine> sourceLines = new ArrayList<SourceAccountingLine>();
505: // set accountinglines to document
506: for (AccountingLineFixture sourceFixture : getSourceAccountingLineParametersFromFixtures()) {
507: sourceLines.add(sourceFixture.createSourceAccountingLine());
508: }
509:
510: return sourceLines;
511: }
512:
513: private List<TargetAccountingLine> generateTargetAccountingLines()
514: throws Exception {
515: List<TargetAccountingLine> targetLines = new ArrayList<TargetAccountingLine>();
516: for (AccountingLineFixture targetFixture : getTargetAccountingLineParametersFromFixtures()) {
517: targetLines.add(targetFixture.createTargetAccountingLine());
518: }
519:
520: return targetLines;
521: }
522:
523: private InternalBillingDocument buildDocument() throws Exception {
524: // put accounting lines into document parameter for later
525: InternalBillingDocument document = (InternalBillingDocument) getDocumentParameterFixture();
526:
527: // set accountinglines to document
528: for (AccountingLineFixture sourceFixture : getSourceAccountingLineParametersFromFixtures()) {
529: sourceFixture.addAsSourceTo(document);
530: }
531:
532: for (AccountingLineFixture targetFixture : getTargetAccountingLineParametersFromFixtures()) {
533: targetFixture.addAsTargetTo(document);
534: }
535:
536: return document;
537: }
538:
539: private void updateSourceAccountingLine(
540: AccountingDocument document, int index, String newAmount) {
541: SourceAccountingLine sourceLine = document
542: .getSourceAccountingLine(index);
543: sourceLine.setAmount(new KualiDecimal(newAmount));
544: }
545:
546: private void updateTargetAccountingLine(
547: AccountingDocument document, int index, String newAmount) {
548: TargetAccountingLine targetLine = document
549: .getTargetAccountingLine(index);
550: targetLine.setAmount(new KualiDecimal(newAmount));
551: }
552:
553: private void deleteSourceAccountingLine(
554: AccountingDocument document, int index) {
555: List sourceLines = document.getSourceAccountingLines();
556: sourceLines.remove(index);
557: document.setSourceAccountingLines(sourceLines);
558: }
559:
560: private void deleteTargetAccountingLine(
561: AccountingDocument document, int index) {
562: List targetLines = document.getTargetAccountingLines();
563: targetLines.remove(index);
564: document.setTargetAccountingLines(targetLines);
565: }
566:
567: private UserNameFixture getInitialUserName() {
568: return RJWEISS;
569: }
570:
571: protected UserNameFixture getTestUserName() {
572: return RORENFRO;
573: }
574:
575: private SourceAccountingLine getSourceAccountingLineAccessibleAccount()
576: throws Exception {
577: return LINE2.createSourceAccountingLine();
578: }
579:
580: private TargetAccountingLine getTargetAccountingLineInaccessibleAccount()
581: throws Exception {
582: return LINE3.createTargetAccountingLine();
583: }
584:
585: private TargetAccountingLine getTargetAccountingLineAccessibleAccount()
586: throws Exception {
587: return LINE2.createTargetAccountingLine();
588: }
589:
590: private SourceAccountingLine getSourceAccountingLineInaccessibleAccount()
591: throws Exception {
592: return LINE3.createSourceAccountingLine();
593: }
594:
595: }
|