001: /*
002: * Copyright 2006-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.purap.document;
017:
018: import java.sql.Date;
019: import java.util.List;
020:
021: import org.apache.commons.lang.StringUtils;
022: import org.apache.ojb.broker.PersistenceBroker;
023: import org.apache.ojb.broker.PersistenceBrokerException;
024: import org.kuali.RicePropertyConstants;
025: import org.kuali.core.bo.Campus;
026: import org.kuali.core.bo.Note;
027: import org.kuali.core.bo.user.UniversalUser;
028: import org.kuali.core.exceptions.UserNotFoundException;
029: import org.kuali.core.rule.event.KualiDocumentEvent;
030: import org.kuali.core.service.UniversalUserService;
031: import org.kuali.core.util.KualiDecimal;
032: import org.kuali.core.util.ObjectUtils;
033: import org.kuali.core.workflow.service.KualiWorkflowInfo;
034: import org.kuali.kfs.context.SpringContext;
035: import org.kuali.module.purap.PurapWorkflowConstants.NodeDetails;
036: import org.kuali.module.purap.bo.AccountsPayableItem;
037: import org.kuali.module.purap.bo.PurchaseOrderItem;
038: import org.kuali.module.purap.service.AccountsPayableDocumentSpecificService;
039: import org.kuali.module.purap.service.PurapService;
040: import org.kuali.module.purap.service.PurchaseOrderService;
041:
042: import edu.iu.uis.eden.EdenConstants;
043: import edu.iu.uis.eden.clientapp.vo.DocumentRouteLevelChangeVO;
044: import edu.iu.uis.eden.clientapp.vo.ReportCriteriaVO;
045: import edu.iu.uis.eden.exception.WorkflowException;
046:
047: /**
048: * Accounts Payable Document Base
049: */
050: public abstract class AccountsPayableDocumentBase extends
051: PurchasingAccountsPayableDocumentBase implements
052: AccountsPayableDocument {
053: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
054: .getLogger(AccountsPayableDocumentBase.class);
055:
056: // SHARED FIELDS BETWEEN PAYMENT REQUEST AND CREDIT MEMO
057: private Date accountsPayableApprovalDate;
058: private String lastActionPerformedByUniversalUserId;
059: private String accountsPayableProcessorIdentifier;
060: private boolean holdIndicator;
061: private Date extractedDate;
062: private Integer purchaseOrderIdentifier;
063: private String processingCampusCode;
064: private String noteLine1Text;
065: private String noteLine2Text;
066: private String noteLine3Text;
067: private boolean continuationAccountIndicator;
068: private boolean closePurchaseOrderIndicator;
069: private boolean reopenPurchaseOrderIndicator;
070:
071: private boolean unmatchedOverride; // not persisted
072:
073: // NOT PERSISTED IN DB
074: // BELOW USED BY ROUTING
075: private String chartOfAccountsCode;
076: private String organizationCode;
077:
078: // NOT PERSISTED IN DB
079: // BELOW USED BY GL ENTRY CREATION
080: private boolean generateEncumbranceEntries;
081: private String debitCreditCodeForGLEntries;
082:
083: // REFERENCE OBJECTS
084: private Campus processingCampus;
085: private transient PurchaseOrderDocument purchaseOrderDocument;
086:
087: /**
088: * Constructs a AccountsPayableDocumentBase
089: */
090: public AccountsPayableDocumentBase() {
091: super ();
092: setUnmatchedOverride(false);
093: }
094:
095: /**
096: * This method is here due to a setter requirement by the htmlControlAttribute
097: *
098: * @param amount - Grand total for document, excluding discount
099: */
100: public void setGrandTotalExcludingDiscount(KualiDecimal amount) {
101: // do nothing
102: }
103:
104: public void setLineItemTotal(KualiDecimal total) {
105: // do nothing, this is so that the jsp won't complain about lineItemTotal have no setter method.
106: }
107:
108: public void setGrandTotal(KualiDecimal total) {
109: // do nothing, this is so that the jsp won't complain about grandTotal have no setter method.
110: }
111:
112: /**
113: * Overriding to stop the deleting of general ledger entries.
114: *
115: * @see org.kuali.kfs.document.GeneralLedgerPostingDocumentBase#removeGeneralLedgerPendingEntries()
116: */
117: @Override
118: protected void removeGeneralLedgerPendingEntries() {
119: // do not delete entries for PREQ or CM (hjs)
120: }
121:
122: /**
123: * @see org.kuali.module.purap.document.AccountsPayableDocument#requiresAccountsPayableReviewRouting()
124: */
125: public boolean requiresAccountsPayableReviewRouting() {
126: return !approvalAtAccountsPayableReviewAllowed();
127: }
128:
129: /**
130: * @see org.kuali.module.purap.document.AccountsPayableDocument#approvalAtAccountsPayableReviewAllowed()
131: */
132: public boolean approvalAtAccountsPayableReviewAllowed() {
133: return !(isAttachmentRequired() && documentHasNoImagesAttached());
134: }
135:
136: /**
137: * Checks whether an attachment is required
138: *
139: * @return - true if attachment is required, otherwise false
140: */
141: protected abstract boolean isAttachmentRequired();
142:
143: /**
144: * Checks all documents notes for attachments.
145: *
146: * @return - true if document does not have an image attached, false otherwise
147: */
148: private boolean documentHasNoImagesAttached() {
149: List boNotes = this .getDocumentBusinessObject().getBoNotes();
150: if (ObjectUtils.isNotNull(boNotes)) {
151: for (Object obj : boNotes) {
152: Note note = (Note) obj;
153: // may need to refresh this attachment because of a bug - see see KULPURAP-1397
154: note.refreshReferenceObject("attachment");
155: if (ObjectUtils.isNotNull(note.getAttachment())) {
156: return false;
157: }
158: }
159: }
160: return true;
161: }
162:
163: /**
164: * @see org.kuali.module.purap.document.PurchasingAccountsPayableDocumentBase#populateDocumentForRouting()
165: */
166: @Override
167: public void populateDocumentForRouting() {
168: if (ObjectUtils.isNotNull(getPurchaseOrderDocument())) {
169: this .setChartOfAccountsCode(getPurchaseOrderDocument()
170: .getChartOfAccountsCode());
171: this .setOrganizationCode(getPurchaseOrderDocument()
172: .getOrganizationCode());
173: if (ObjectUtils.isNull(this .getPurchaseOrderDocument()
174: .getDocumentHeader().getDocumentNumber())) {
175: this .getPurchaseOrderDocument().refreshReferenceObject(
176: RicePropertyConstants.DOCUMENT_HEADER);
177: }
178: }
179: super .populateDocumentForRouting();
180: }
181:
182: /**
183: * Calls a custom prepare for save method, as the super class does GL entry creation that causes problems with AP documents.
184: *
185: * @see org.kuali.module.purap.document.PurchasingAccountsPayableDocumentBase#prepareForSave(org.kuali.core.rule.event.KualiDocumentEvent)
186: */
187: @Override
188: public void prepareForSave(KualiDocumentEvent event) {
189:
190: // copied from super because we can't call super for AP docs
191: customPrepareForSave(event);
192:
193: // DO NOT CALL SUPER HERE!! Cannot call super because it will mess up the GL entry creation process (hjs)
194: // super.prepareForSave(event);
195: }
196:
197: /**
198: * Helper method to be called from custom prepare for save and to be overriden by sub class.
199: *
200: * @return - Po Document Type
201: */
202: public abstract String getPoDocumentTypeForAccountsPayableDocumentCancel();
203:
204: /**
205: * @see org.kuali.core.document.DocumentBase#handleRouteLevelChange(edu.iu.uis.eden.clientapp.vo.DocumentRouteLevelChangeVO)
206: */
207: @Override
208: public void handleRouteLevelChange(
209: DocumentRouteLevelChangeVO levelChangeEvent) {
210: LOG.debug("handleRouteLevelChange() started");
211: super .handleRouteLevelChange(levelChangeEvent);
212: try {
213: String newNodeName = levelChangeEvent.getNewNodeName();
214: if (processNodeChange(newNodeName, levelChangeEvent
215: .getOldNodeName())) {
216: if (StringUtils.isNotBlank(newNodeName)) {
217: ReportCriteriaVO reportCriteriaVO = new ReportCriteriaVO(
218: Long.valueOf(getDocumentNumber()));
219: reportCriteriaVO.setTargetNodeName(newNodeName);
220: if (SpringContext
221: .getBean(KualiWorkflowInfo.class)
222: .documentWillHaveAtLeastOneActionRequest(
223: reportCriteriaVO,
224: new String[] {
225: EdenConstants.ACTION_REQUEST_APPROVE_REQ,
226: EdenConstants.ACTION_REQUEST_COMPLETE_REQ })) {
227: NodeDetails nodeDetailEnum = getNodeDetailEnum(newNodeName);
228: if (ObjectUtils.isNotNull(nodeDetailEnum)) {
229: String statusCode = nodeDetailEnum
230: .getAwaitingStatusCode();
231: if (StringUtils.isNotBlank(statusCode)) {
232: SpringContext.getBean(
233: PurapService.class)
234: .updateStatus(this , statusCode);
235: saveDocumentFromPostProcessing();
236: } else {
237: LOG
238: .debug("Document with id "
239: + getDocumentNumber()
240: + " will stop in route node '"
241: + newNodeName
242: + "' but no awaiting status found to set");
243: }
244: } else {
245: LOG
246: .debug("Document with id "
247: + getDocumentNumber()
248: + " will not stop in route node '"
249: + newNodeName
250: + "' but node cannot be found to get awaiting status");
251: }
252: } else {
253: LOG.debug("Document with id "
254: + getDocumentNumber()
255: + " will not stop in route node '"
256: + newNodeName + "'");
257: }
258: }
259: }
260: } catch (WorkflowException e) {
261: String errorMsg = "Workflow Error found checking actions requests on document with id "
262: + getDocumentNumber()
263: + ". *** WILL NOT UPDATE PURAP STATUS ***";
264: LOG.warn(errorMsg, e);
265: }
266: }
267:
268: /**
269: * Hook to allow processing after a route level is passed.
270: *
271: * @param newNodeName - current route level
272: * @param oldNodeName - previous route level
273: * @return - true if process completes to valid state
274: */
275: public abstract boolean processNodeChange(String newNodeName,
276: String oldNodeName);
277:
278: /**
279: * Retrieves node details object based on name.
280: *
281: * @param nodeName - route level
282: * @return - Information about the supplied route level
283: */
284: public abstract NodeDetails getNodeDetailEnum(String nodeName);
285:
286: /**
287: * Hook point to allow processing after a save.
288: */
289: public abstract void saveDocumentFromPostProcessing();
290:
291: // GETTERS AND SETTERS
292: public Integer getPurchaseOrderIdentifier() {
293: return purchaseOrderIdentifier;
294: }
295:
296: public void setPurchaseOrderIdentifier(
297: Integer purchaseOrderIdentifier) {
298: this .purchaseOrderIdentifier = purchaseOrderIdentifier;
299: }
300:
301: public String getAccountsPayableProcessorIdentifier() {
302: return accountsPayableProcessorIdentifier;
303: }
304:
305: public void setAccountsPayableProcessorIdentifier(
306: String accountsPayableProcessorIdentifier) {
307: this .accountsPayableProcessorIdentifier = accountsPayableProcessorIdentifier;
308: }
309:
310: public String getLastActionPerformedByUniversalUserId() {
311: return lastActionPerformedByUniversalUserId;
312: }
313:
314: public void setLastActionPerformedByUniversalUserId(
315: String lastActionPerformedByUniversalUserId) {
316: this .lastActionPerformedByUniversalUserId = lastActionPerformedByUniversalUserId;
317: }
318:
319: public String getProcessingCampusCode() {
320: return processingCampusCode;
321: }
322:
323: public void setProcessingCampusCode(String processingCampusCode) {
324: this .processingCampusCode = processingCampusCode;
325: }
326:
327: public Date getAccountsPayableApprovalDate() {
328: return accountsPayableApprovalDate;
329: }
330:
331: public void setAccountsPayableApprovalDate(
332: Date accountsPayableApprovalDate) {
333: this .accountsPayableApprovalDate = accountsPayableApprovalDate;
334: }
335:
336: public Date getExtractedDate() {
337: return extractedDate;
338: }
339:
340: public void setExtractedDate(Date extractedDate) {
341: this .extractedDate = extractedDate;
342: }
343:
344: public boolean isHoldIndicator() {
345: return holdIndicator;
346: }
347:
348: public void setHoldIndicator(boolean holdIndicator) {
349: this .holdIndicator = holdIndicator;
350: }
351:
352: public String getNoteLine1Text() {
353: return noteLine1Text;
354: }
355:
356: public void setNoteLine1Text(String noteLine1Text) {
357: this .noteLine1Text = noteLine1Text;
358: }
359:
360: public String getNoteLine2Text() {
361: return noteLine2Text;
362: }
363:
364: public void setNoteLine2Text(String noteLine2Text) {
365: this .noteLine2Text = noteLine2Text;
366: }
367:
368: public String getNoteLine3Text() {
369: return noteLine3Text;
370: }
371:
372: public void setNoteLine3Text(String noteLine3Text) {
373: this .noteLine3Text = noteLine3Text;
374: }
375:
376: public Campus getProcessingCampus() {
377: return processingCampus;
378: }
379:
380: public String getChartOfAccountsCode() {
381: return chartOfAccountsCode;
382: }
383:
384: public void setChartOfAccountsCode(String chartOfAccountsCode) {
385: this .chartOfAccountsCode = chartOfAccountsCode;
386: }
387:
388: public String getOrganizationCode() {
389: return organizationCode;
390: }
391:
392: public void setOrganizationCode(String organizationCode) {
393: this .organizationCode = organizationCode;
394: }
395:
396: public boolean isGenerateEncumbranceEntries() {
397: return generateEncumbranceEntries;
398: }
399:
400: public void setGenerateEncumbranceEntries(
401: boolean generateEncumbranceEntries) {
402: this .generateEncumbranceEntries = generateEncumbranceEntries;
403: }
404:
405: /**
406: * @see org.kuali.module.purap.document.AccountsPayableDocument#getPurchaseOrderDocument()
407: */
408: public PurchaseOrderDocument getPurchaseOrderDocument() {
409: if ((ObjectUtils.isNull(purchaseOrderDocument) || ObjectUtils
410: .isNull(purchaseOrderDocument
411: .getPurapDocumentIdentifier()))
412: && (ObjectUtils.isNotNull(getPurchaseOrderIdentifier()))) {
413: setPurchaseOrderDocument(SpringContext.getBean(
414: PurchaseOrderService.class)
415: .getCurrentPurchaseOrder(
416: this .getPurchaseOrderIdentifier()));
417: }
418: return purchaseOrderDocument;
419: }
420:
421: /**
422: * @see org.kuali.module.purap.document.AccountsPayableDocument#setPurchaseOrderDocument(org.kuali.module.purap.document.PurchaseOrderDocument)
423: */
424: public void setPurchaseOrderDocument(
425: PurchaseOrderDocument purchaseOrderDocument) {
426: if (ObjectUtils.isNull(purchaseOrderDocument)) {
427: // KUALI-PURAP 1185 PO Id not being set to null, instead throwing error on main screen that value is invalid.
428: // setPurchaseOrderIdentifier(null);
429: this .purchaseOrderDocument = null;
430: } else {
431: if (ObjectUtils.isNotNull(purchaseOrderDocument
432: .getPurapDocumentIdentifier())) {
433: setPurchaseOrderIdentifier(purchaseOrderDocument
434: .getPurapDocumentIdentifier());
435: }
436: this .purchaseOrderDocument = purchaseOrderDocument;
437: }
438: }
439:
440: public boolean isClosePurchaseOrderIndicator() {
441: return closePurchaseOrderIndicator;
442: }
443:
444: public void setClosePurchaseOrderIndicator(
445: boolean closePurchaseOrderIndicator) {
446: this .closePurchaseOrderIndicator = closePurchaseOrderIndicator;
447: }
448:
449: public boolean isReopenPurchaseOrderIndicator() {
450: return reopenPurchaseOrderIndicator;
451: }
452:
453: public void setReopenPurchaseOrderIndicator(
454: boolean reopenPurchaseOrderIndicator) {
455: this .reopenPurchaseOrderIndicator = reopenPurchaseOrderIndicator;
456: }
457:
458: // Helper methods
459: /**
460: * Retrieves the universal user object for the last person to perform an action on the document.
461: */
462: public UniversalUser getLastActionPerformedByUser() {
463: try {
464: UniversalUser user = SpringContext.getBean(
465: UniversalUserService.class).getUniversalUser(
466: getLastActionPerformedByUniversalUserId());
467: return user;
468: } catch (UserNotFoundException unfe) {
469: return null;
470: }
471: }
472:
473: /**
474: * Retrieves the person name for the last person to perform an action on the document.
475: *
476: * @return - the person's name who last performed an action on the document.
477: */
478: public String getLastActionPerformedByPersonName() {
479: UniversalUser user = getLastActionPerformedByUser();
480: if (ObjectUtils.isNull(user)) {
481: return "";
482: } else {
483: return user.getPersonName();
484: }
485: }
486:
487: public String getDebitCreditCodeForGLEntries() {
488: return debitCreditCodeForGLEntries;
489: }
490:
491: public void setDebitCreditCodeForGLEntries(
492: String debitCreditCodeForGLEntries) {
493: this .debitCreditCodeForGLEntries = debitCreditCodeForGLEntries;
494: }
495:
496: public boolean isUnmatchedOverride() {
497: return unmatchedOverride;
498: }
499:
500: public void setUnmatchedOverride(boolean unmatchedOverride) {
501: this .unmatchedOverride = unmatchedOverride;
502: }
503:
504: /**
505: * @see org.kuali.module.purap.document.AccountsPayableDocument#getGrandTotal()
506: */
507: public abstract KualiDecimal getGrandTotal();
508:
509: /**
510: * @see org.kuali.module.purap.document.AccountsPayableDocument#getInitialAmount()
511: */
512: public abstract KualiDecimal getInitialAmount();
513:
514: public boolean isContinuationAccountIndicator() {
515: return continuationAccountIndicator;
516: }
517:
518: public void setContinuationAccountIndicator(
519: boolean continuationAccountIndicator) {
520: this .continuationAccountIndicator = continuationAccountIndicator;
521: }
522:
523: public boolean isExtracted() {
524: return (ObjectUtils.isNotNull(getExtractedDate()));
525: }
526:
527: public abstract AccountsPayableDocumentSpecificService getDocumentSpecificService();
528:
529: public AccountsPayableItem getAPItemFromPOItem(PurchaseOrderItem poi) {
530: for (AccountsPayableItem preqItem : (List<AccountsPayableItem>) this
531: .getItems()) {
532: if (preqItem.getItemType()
533: .isItemTypeAboveTheLineIndicator()) {
534: if (preqItem.getItemLineNumber().compareTo(
535: poi.getItemLineNumber()) == 0) {
536: return preqItem;
537: }
538: } else {
539: return (AccountsPayableItem) SpringContext.getBean(
540: PurapService.class).getBelowTheLineByType(this ,
541: poi.getItemType());
542: }
543: }
544: return null;
545: }
546:
547: /**
548: * @see org.kuali.module.purap.document.PurchasingAccountsPayableDocumentBase#getItemClass()
549: */
550: public Class getItemClass() {
551: return null;
552: }
553:
554: /**
555: * @see org.kuali.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentIfPossible()
556: */
557: public PurchasingAccountsPayableDocument getPurApSourceDocumentIfPossible() {
558: return null;
559: }
560:
561: /**
562: * @see org.kuali.module.purap.document.PurchasingAccountsPayableDocumentBase#getPurApSourceDocumentLabelIfPossible()
563: */
564: public String getPurApSourceDocumentLabelIfPossible() {
565: return null;
566: }
567:
568: /**
569: * @see org.kuali.core.bo.PersistableBusinessObjectBase#afterLookup(org.apache.ojb.broker.PersistenceBroker)
570: */
571: @Override
572: public void afterLookup(PersistenceBroker persistenceBroker)
573: throws PersistenceBrokerException {
574: super .afterLookup(persistenceBroker);
575: if ((ObjectUtils.isNull(purchaseOrderDocument) || ObjectUtils
576: .isNull(purchaseOrderDocument
577: .getPurapDocumentIdentifier()))
578: && (ObjectUtils.isNotNull(getPurchaseOrderIdentifier()))) {
579: this .setPurchaseOrderDocument(SpringContext.getBean(
580: PurchaseOrderService.class)
581: .getCurrentPurchaseOrder(
582: this.getPurchaseOrderIdentifier()));
583: if (ObjectUtils.isNull(this.getPurchaseOrderDocument()
584: .getDocumentHeader().getDocumentNumber())) {
585: this.getPurchaseOrderDocument().refreshReferenceObject(
586: RicePropertyConstants.DOCUMENT_HEADER);
587: }
588: }
589: }
590: }
|